@hazbase/simplicity 0.0.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.
- package/LICENSE +182 -0
- package/README.md +778 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +628 -0
- package/dist/client/ContractFactory.d.ts +13 -0
- package/dist/client/ContractFactory.js +50 -0
- package/dist/client/DeployedContract.d.ts +12 -0
- package/dist/client/DeployedContract.js +43 -0
- package/dist/client/SimplicityClient.d.ts +21 -0
- package/dist/client/SimplicityClient.js +65 -0
- package/dist/core/artifact.d.ts +6 -0
- package/dist/core/artifact.js +100 -0
- package/dist/core/compiler.d.ts +3 -0
- package/dist/core/compiler.js +117 -0
- package/dist/core/errors.d.ts +33 -0
- package/dist/core/errors.js +70 -0
- package/dist/core/executor.d.ts +5 -0
- package/dist/core/executor.js +664 -0
- package/dist/core/presets.d.ts +16 -0
- package/dist/core/presets.js +251 -0
- package/dist/core/rpc.d.ts +7 -0
- package/dist/core/rpc.js +37 -0
- package/dist/core/summary.d.ts +6 -0
- package/dist/core/summary.js +27 -0
- package/dist/core/templating.d.ts +2 -0
- package/dist/core/templating.js +17 -0
- package/dist/core/toolchain.d.ts +14 -0
- package/dist/core/toolchain.js +82 -0
- package/dist/core/types.d.ts +258 -0
- package/dist/core/types.js +2 -0
- package/dist/gasless/RelayerClient.d.ts +13 -0
- package/dist/gasless/RelayerClient.js +76 -0
- package/dist/gasless/types.d.ts +144 -0
- package/dist/gasless/types.js +2 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +35 -0
- package/dist/presets/htlc.simf.tmpl +35 -0
- package/dist/presets/manifest.d.ts +1 -0
- package/dist/presets/manifest.js +5 -0
- package/dist/presets/p2pk.simf.tmpl +4 -0
- package/dist/presets/p2pkLockHeight.simf.tmpl +5 -0
- package/dist/presets/transferWithTimeout.simf.tmpl +26 -0
- package/package.json +45 -0
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,628 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const promises_1 = require("node:fs/promises");
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const artifact_1 = require("./core/artifact");
|
|
10
|
+
const presets_1 = require("./core/presets");
|
|
11
|
+
const errors_1 = require("./core/errors");
|
|
12
|
+
const SimplicityClient_1 = require("./client/SimplicityClient");
|
|
13
|
+
function getArg(name, defaultValue) {
|
|
14
|
+
const index = process.argv.indexOf(`--${name}`);
|
|
15
|
+
if (index === -1)
|
|
16
|
+
return defaultValue;
|
|
17
|
+
const value = process.argv[index + 1];
|
|
18
|
+
if (!value || value.startsWith("--"))
|
|
19
|
+
return defaultValue;
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
function getMultiArgs(name) {
|
|
23
|
+
const values = [];
|
|
24
|
+
for (let i = 0; i < process.argv.length; i += 1) {
|
|
25
|
+
if (process.argv[i] === `--${name}`) {
|
|
26
|
+
const value = process.argv[i + 1];
|
|
27
|
+
if (value && !value.startsWith("--"))
|
|
28
|
+
values.push(value);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return values;
|
|
32
|
+
}
|
|
33
|
+
function hasFlag(name) {
|
|
34
|
+
return process.argv.includes(`--${name}`);
|
|
35
|
+
}
|
|
36
|
+
function requireArg(name) {
|
|
37
|
+
const value = getArg(name);
|
|
38
|
+
if (!value)
|
|
39
|
+
throw new Error(`Missing required arg: --${name}`);
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
function parseAssignments(values) {
|
|
43
|
+
return Object.fromEntries(values.map((entry) => {
|
|
44
|
+
const [key, raw] = entry.split("=", 2);
|
|
45
|
+
const asNumber = Number(raw);
|
|
46
|
+
return [key, Number.isFinite(asNumber) && String(asNumber) === raw ? asNumber : raw];
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
function parseWitnessAssignments(values) {
|
|
50
|
+
return Object.fromEntries(values.map((entry) => {
|
|
51
|
+
const [left, value] = entry.split("=", 2);
|
|
52
|
+
const [name, type] = left.split(":", 2);
|
|
53
|
+
if (!name || !type || value === undefined) {
|
|
54
|
+
throw new Error(`Invalid --witness-value format: ${entry}`);
|
|
55
|
+
}
|
|
56
|
+
return [name, { type, value }];
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
function parseWitnessSigners(values) {
|
|
60
|
+
return Object.fromEntries(values.map((entry) => {
|
|
61
|
+
const [name, privkeyHex] = entry.split("=", 2);
|
|
62
|
+
if (!name || !privkeyHex) {
|
|
63
|
+
throw new Error(`Invalid --witness-signer format: ${entry}`);
|
|
64
|
+
}
|
|
65
|
+
return [name, { type: "schnorrPrivkeyHex", privkeyHex }];
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
function resolveConfig() {
|
|
69
|
+
return {
|
|
70
|
+
network: getArg("network", "liquidtestnet"),
|
|
71
|
+
rpc: {
|
|
72
|
+
url: getArg("rpc-url", process.env.ELEMENTS_RPC_URL ?? "http://127.0.0.1:18884"),
|
|
73
|
+
username: getArg("rpc-user", process.env.ELEMENTS_RPC_USER ?? "<rpc-user>"),
|
|
74
|
+
password: getArg("rpc-password", process.env.ELEMENTS_RPC_PASSWORD ?? "<rpc-password>"),
|
|
75
|
+
wallet: getArg("wallet", process.env.ELEMENTS_RPC_WALLET),
|
|
76
|
+
},
|
|
77
|
+
toolchain: {
|
|
78
|
+
simcPath: getArg("simc-path", process.env.SIMC_PATH ?? "simc"),
|
|
79
|
+
halSimplicityPath: getArg("hal-path", process.env.HAL_SIMPLICITY_PATH ?? "hal-simplicity"),
|
|
80
|
+
elementsCliPath: getArg("elements-cli-path", process.env.ELEMENTS_CLI_PATH ?? "eltc"),
|
|
81
|
+
},
|
|
82
|
+
relayer: getArg("relayer")
|
|
83
|
+
? {
|
|
84
|
+
baseUrl: getArg("relayer"),
|
|
85
|
+
apiKey: getArg("api-key"),
|
|
86
|
+
}
|
|
87
|
+
: undefined,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function printJson(value) {
|
|
91
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
92
|
+
}
|
|
93
|
+
function indent(text, spaces = 2) {
|
|
94
|
+
const prefix = " ".repeat(spaces);
|
|
95
|
+
return text
|
|
96
|
+
.split("\n")
|
|
97
|
+
.map((line) => `${prefix}${line}`)
|
|
98
|
+
.join("\n");
|
|
99
|
+
}
|
|
100
|
+
function formatParamArgs(params) {
|
|
101
|
+
return Object.entries(params)
|
|
102
|
+
.map(([key, value]) => `--param ${key}=${value}`)
|
|
103
|
+
.join(" ");
|
|
104
|
+
}
|
|
105
|
+
function formatWitnessCliArgs(preset) {
|
|
106
|
+
const parts = [];
|
|
107
|
+
for (const [name, signer] of Object.entries(preset.exampleWitness?.signers ?? {})) {
|
|
108
|
+
parts.push(`--witness-signer ${name}=${signer.privkeyHex}`);
|
|
109
|
+
}
|
|
110
|
+
for (const [name, value] of Object.entries(preset.exampleWitness?.values ?? {})) {
|
|
111
|
+
parts.push(`--witness-value '${name}:${value.type}=${value.value}'`);
|
|
112
|
+
}
|
|
113
|
+
return parts.join(" ");
|
|
114
|
+
}
|
|
115
|
+
function formatWitnessSchema(preset) {
|
|
116
|
+
const entries = Object.entries(preset.witnessSchema ?? {});
|
|
117
|
+
if (entries.length === 0)
|
|
118
|
+
return " (none)";
|
|
119
|
+
return entries
|
|
120
|
+
.map(([name, spec]) => {
|
|
121
|
+
const alias = spec.signerAlias ? ` [named signer: ${spec.signerAlias}]` : "";
|
|
122
|
+
const description = spec.description ? ` - ${spec.description}` : "";
|
|
123
|
+
return ` - ${name}: ${spec.type}${alias}${description}`;
|
|
124
|
+
})
|
|
125
|
+
.join("\n");
|
|
126
|
+
}
|
|
127
|
+
function formatParamSchema(preset) {
|
|
128
|
+
return Object.entries(preset.parameterSchema)
|
|
129
|
+
.map(([name, kind]) => ` - ${name}: ${kind}`)
|
|
130
|
+
.join("\n");
|
|
131
|
+
}
|
|
132
|
+
function formatExecuteSupport(preset) {
|
|
133
|
+
return [
|
|
134
|
+
` direct execute: ${preset.executionProfile.supportsDirectExecute ? "yes" : "no"}`,
|
|
135
|
+
` relayer execute: ${preset.executionProfile.supportsRelayerExecute ? "yes" : "no"}`,
|
|
136
|
+
` gasless: ${preset.executionProfile.supportsGasless ? "yes" : "no"}`,
|
|
137
|
+
` default fee sat: ${preset.executionProfile.defaultFeeSat}`,
|
|
138
|
+
` utxo policy: ${preset.executionProfile.recommendedUtxoPolicy}`,
|
|
139
|
+
].join("\n");
|
|
140
|
+
}
|
|
141
|
+
function formatPresetHelp(preset) {
|
|
142
|
+
const compileCommand = [
|
|
143
|
+
"simplicity-cli preset compile",
|
|
144
|
+
`--preset ${preset.id}`,
|
|
145
|
+
formatParamArgs(preset.exampleParams),
|
|
146
|
+
"--artifact ./artifact.json",
|
|
147
|
+
].join(" ");
|
|
148
|
+
const executeCommand = [
|
|
149
|
+
"simplicity-cli contract execute",
|
|
150
|
+
"--artifact ./artifact.json",
|
|
151
|
+
"--wallet simplicity-test",
|
|
152
|
+
"--privkey <primary-privkey-hex>",
|
|
153
|
+
"--to-address tex1...",
|
|
154
|
+
formatWitnessCliArgs(preset),
|
|
155
|
+
]
|
|
156
|
+
.filter(Boolean)
|
|
157
|
+
.join(" ");
|
|
158
|
+
const executeGaslessCommand = [
|
|
159
|
+
"simplicity-cli contract execute-gasless",
|
|
160
|
+
"--artifact ./artifact.json",
|
|
161
|
+
"--wallet simplicity-test",
|
|
162
|
+
"--relayer http://127.0.0.1:3000",
|
|
163
|
+
"--api-key <relayer-api-key>",
|
|
164
|
+
"--from-label demo-user",
|
|
165
|
+
"--privkey <primary-privkey-hex>",
|
|
166
|
+
"--to-address tex1...",
|
|
167
|
+
formatWitnessCliArgs(preset),
|
|
168
|
+
]
|
|
169
|
+
.filter(Boolean)
|
|
170
|
+
.join(" ");
|
|
171
|
+
const tsSnippet = [
|
|
172
|
+
"const compiled = await sdk.compileFromPreset({",
|
|
173
|
+
` preset: "${preset.id}",`,
|
|
174
|
+
" params: " + JSON.stringify(preset.exampleParams, null, 2).replace(/\n/g, "\n "),
|
|
175
|
+
"});",
|
|
176
|
+
"",
|
|
177
|
+
"const result = await compiled.at().execute({",
|
|
178
|
+
' wallet: "simplicity-test",',
|
|
179
|
+
' toAddress: "tex1...",',
|
|
180
|
+
' signer: { type: "schnorrPrivkeyHex", privkeyHex: "<primary-privkey-hex>" },',
|
|
181
|
+
preset.exampleWitness
|
|
182
|
+
? " witness: " + JSON.stringify(preset.exampleWitness, null, 2).replace(/\n/g, "\n ") + ","
|
|
183
|
+
: "",
|
|
184
|
+
"});",
|
|
185
|
+
]
|
|
186
|
+
.filter(Boolean)
|
|
187
|
+
.join("\n");
|
|
188
|
+
return [
|
|
189
|
+
`${preset.title} (${preset.id})`,
|
|
190
|
+
preset.description,
|
|
191
|
+
"",
|
|
192
|
+
"Parameters:",
|
|
193
|
+
formatParamSchema(preset),
|
|
194
|
+
"",
|
|
195
|
+
"Witness:",
|
|
196
|
+
formatWitnessSchema(preset),
|
|
197
|
+
"",
|
|
198
|
+
"Execution:",
|
|
199
|
+
formatExecuteSupport(preset),
|
|
200
|
+
"",
|
|
201
|
+
"Example Params:",
|
|
202
|
+
indent(JSON.stringify(preset.exampleParams, null, 2)),
|
|
203
|
+
"",
|
|
204
|
+
"Example Witness:",
|
|
205
|
+
indent(JSON.stringify(preset.exampleWitness ?? {}, null, 2)),
|
|
206
|
+
"",
|
|
207
|
+
"Compile Command:",
|
|
208
|
+
` ${compileCommand}`,
|
|
209
|
+
"",
|
|
210
|
+
"Execute Command:",
|
|
211
|
+
` ${executeCommand}`,
|
|
212
|
+
"",
|
|
213
|
+
"Gasless Execute Command:",
|
|
214
|
+
` ${executeGaslessCommand}`,
|
|
215
|
+
"",
|
|
216
|
+
"TypeScript Snippet:",
|
|
217
|
+
indent(tsSnippet),
|
|
218
|
+
].join("\n");
|
|
219
|
+
}
|
|
220
|
+
function buildScaffoldData(preset) {
|
|
221
|
+
const compileCommand = [
|
|
222
|
+
"simplicity-cli preset compile",
|
|
223
|
+
`--preset ${preset.id}`,
|
|
224
|
+
formatParamArgs(preset.exampleParams),
|
|
225
|
+
"--artifact ./artifact.json",
|
|
226
|
+
].join(" ");
|
|
227
|
+
const executeCommand = [
|
|
228
|
+
"simplicity-cli contract execute",
|
|
229
|
+
"--artifact ./artifact.json",
|
|
230
|
+
"--wallet simplicity-test",
|
|
231
|
+
"--privkey <primary-privkey-hex>",
|
|
232
|
+
"--to-address tex1...",
|
|
233
|
+
formatWitnessCliArgs(preset),
|
|
234
|
+
"--broadcast",
|
|
235
|
+
]
|
|
236
|
+
.filter(Boolean)
|
|
237
|
+
.join(" ");
|
|
238
|
+
const gaslessCommand = [
|
|
239
|
+
"simplicity-cli contract execute-gasless",
|
|
240
|
+
"--artifact ./artifact.json",
|
|
241
|
+
"--wallet simplicity-test",
|
|
242
|
+
"--relayer http://127.0.0.1:3000",
|
|
243
|
+
"--api-key <relayer-api-key>",
|
|
244
|
+
"--from-label demo-user",
|
|
245
|
+
"--privkey <primary-privkey-hex>",
|
|
246
|
+
"--to-address tex1...",
|
|
247
|
+
formatWitnessCliArgs(preset),
|
|
248
|
+
"--broadcast",
|
|
249
|
+
]
|
|
250
|
+
.filter(Boolean)
|
|
251
|
+
.join(" ");
|
|
252
|
+
const paramsJson = JSON.stringify(preset.exampleParams, null, 2);
|
|
253
|
+
const witnessJson = JSON.stringify(preset.exampleWitness ?? {}, null, 2);
|
|
254
|
+
const tsExample = [
|
|
255
|
+
'import { createSimplicityClient } from "@hazbase/simplicity";',
|
|
256
|
+
"",
|
|
257
|
+
"async function main() {",
|
|
258
|
+
" const sdk = createSimplicityClient({",
|
|
259
|
+
' network: "liquidtestnet",',
|
|
260
|
+
" rpc: {",
|
|
261
|
+
' url: "http://127.0.0.1:18884",',
|
|
262
|
+
' username: process.env.ELEMENTS_RPC_USER || "<rpc-user>",',
|
|
263
|
+
' password: process.env.ELEMENTS_RPC_PASSWORD || "<rpc-password>",',
|
|
264
|
+
' wallet: "simplicity-test",',
|
|
265
|
+
" },",
|
|
266
|
+
" toolchain: {",
|
|
267
|
+
' simcPath: "simc",',
|
|
268
|
+
' halSimplicityPath: "hal-simplicity",',
|
|
269
|
+
' elementsCliPath: "eltc",',
|
|
270
|
+
" },",
|
|
271
|
+
" });",
|
|
272
|
+
"",
|
|
273
|
+
" const compiled = await sdk.compileFromPreset({",
|
|
274
|
+
` preset: "${preset.id}",`,
|
|
275
|
+
` params: ${paramsJson.replace(/\n/g, "\n ")},`,
|
|
276
|
+
" });",
|
|
277
|
+
"",
|
|
278
|
+
" const result = await compiled.at().execute({",
|
|
279
|
+
' wallet: "simplicity-test",',
|
|
280
|
+
' toAddress: "tex1...",',
|
|
281
|
+
' signer: { type: "schnorrPrivkeyHex", privkeyHex: "<primary-privkey-hex>" },',
|
|
282
|
+
preset.exampleWitness ? ` witness: ${witnessJson.replace(/\n/g, "\n ")},` : "",
|
|
283
|
+
" });",
|
|
284
|
+
"",
|
|
285
|
+
" console.log(result.summaryHash);",
|
|
286
|
+
"}",
|
|
287
|
+
"",
|
|
288
|
+
"main().catch(console.error);",
|
|
289
|
+
]
|
|
290
|
+
.filter(Boolean)
|
|
291
|
+
.join("\n");
|
|
292
|
+
return { compileCommand, executeCommand, gaslessCommand, paramsJson, witnessJson, tsExample };
|
|
293
|
+
}
|
|
294
|
+
async function writeScaffoldFiles(writeDir, preset) {
|
|
295
|
+
const dir = node_path_1.default.resolve(writeDir);
|
|
296
|
+
await (0, promises_1.mkdir)(dir, { recursive: true });
|
|
297
|
+
const scaffold = buildScaffoldData(preset);
|
|
298
|
+
const files = [
|
|
299
|
+
["params.example.json", `${scaffold.paramsJson}\n`],
|
|
300
|
+
["witness.example.json", `${scaffold.witnessJson}\n`],
|
|
301
|
+
["compile.command.txt", `${scaffold.compileCommand}\n`],
|
|
302
|
+
["execute.command.txt", `${scaffold.executeCommand}\n`],
|
|
303
|
+
["execute-gasless.command.txt", `${scaffold.gaslessCommand}\n`],
|
|
304
|
+
[
|
|
305
|
+
".env.example",
|
|
306
|
+
[
|
|
307
|
+
"ELEMENTS_RPC_URL=http://127.0.0.1:18884",
|
|
308
|
+
"ELEMENTS_RPC_USER=<rpc-user>",
|
|
309
|
+
"ELEMENTS_RPC_PASSWORD=<rpc-password>",
|
|
310
|
+
"ELEMENTS_RPC_WALLET=simplicity-test",
|
|
311
|
+
"SIMPLICITY_RELAYER_URL=http://127.0.0.1:3000",
|
|
312
|
+
"SIMPLICITY_RELAYER_API_KEY=<relayer-api-key>",
|
|
313
|
+
"SIMPLICITY_PRIMARY_PRIVKEY=<primary-privkey-hex>",
|
|
314
|
+
].join("\n") + "\n",
|
|
315
|
+
],
|
|
316
|
+
[
|
|
317
|
+
"fund.command.txt",
|
|
318
|
+
[
|
|
319
|
+
"# Compile first to get artifact.json, then fund the contract address shown in deployment output.",
|
|
320
|
+
'eltc -rpcwallet=simplicity-test sendtoaddress "<contract-address>" 0.00002',
|
|
321
|
+
].join("\n") + "\n",
|
|
322
|
+
],
|
|
323
|
+
[`${preset.id}.example.ts`, `${scaffold.tsExample}\n`],
|
|
324
|
+
];
|
|
325
|
+
await Promise.all(files.map(([name, content]) => (0, promises_1.writeFile)(node_path_1.default.join(dir, name), content, "utf8")));
|
|
326
|
+
return files.map(([name]) => node_path_1.default.join(dir, name));
|
|
327
|
+
}
|
|
328
|
+
function formatUtxoList(utxos) {
|
|
329
|
+
if (utxos.length === 0)
|
|
330
|
+
return " (none)";
|
|
331
|
+
return utxos
|
|
332
|
+
.map((utxo) => {
|
|
333
|
+
const state = utxo.confirmed ? `confirmed@${utxo.height ?? "?"}` : "unconfirmed";
|
|
334
|
+
return ` - ${utxo.txid}:${utxo.vout} amountSat=${utxo.sat} ${state}`;
|
|
335
|
+
})
|
|
336
|
+
.join("\n");
|
|
337
|
+
}
|
|
338
|
+
function classifyArtifactStatus(utxos) {
|
|
339
|
+
if (utxos === null)
|
|
340
|
+
return "rpc-unavailable";
|
|
341
|
+
if (utxos.length === 0)
|
|
342
|
+
return "unfunded";
|
|
343
|
+
if (utxos.some((utxo) => utxo.confirmed && utxo.sat > 0))
|
|
344
|
+
return "executable";
|
|
345
|
+
return "unconfirmed-only";
|
|
346
|
+
}
|
|
347
|
+
function formatArtifactHelp(artifact, preset, utxos) {
|
|
348
|
+
const status = classifyArtifactStatus(utxos);
|
|
349
|
+
const ready = status === "executable";
|
|
350
|
+
const deployment = [
|
|
351
|
+
` contract address: ${artifact.compiled.contractAddress}`,
|
|
352
|
+
` cmr: ${artifact.compiled.cmr}`,
|
|
353
|
+
` internal key: ${artifact.compiled.internalKey}`,
|
|
354
|
+
` network: ${artifact.network}`,
|
|
355
|
+
` source mode: ${artifact.source.mode}`,
|
|
356
|
+
` preset: ${artifact.source.preset ?? "(custom file)"}`,
|
|
357
|
+
` status: ${status}`,
|
|
358
|
+
` ready: ${ready ? "yes" : "no"}`,
|
|
359
|
+
].join("\n");
|
|
360
|
+
const compileSource = artifact.source.simfPath ?? artifact.legacy?.simfTemplatePath ?? "(unknown)";
|
|
361
|
+
const templateVars = artifact.source.templateVars ?? {};
|
|
362
|
+
const inspectCommand = `simplicity-cli contract inspect --artifact ./artifact.json --wallet simplicity-test --privkey <privkey-hex> --to-address tex1...`;
|
|
363
|
+
const executeCommand = `simplicity-cli contract execute --artifact ./artifact.json --wallet simplicity-test --privkey <privkey-hex> --to-address tex1... --broadcast`;
|
|
364
|
+
return [
|
|
365
|
+
"Artifact",
|
|
366
|
+
"",
|
|
367
|
+
"Deployment:",
|
|
368
|
+
deployment,
|
|
369
|
+
"",
|
|
370
|
+
"Source:",
|
|
371
|
+
` simf: ${compileSource}`,
|
|
372
|
+
` created at: ${artifact.createdAt}`,
|
|
373
|
+
` sdk version: ${artifact.metadata.sdkVersion}`,
|
|
374
|
+
"",
|
|
375
|
+
"Template Vars:",
|
|
376
|
+
indent(JSON.stringify(templateVars, null, 2)),
|
|
377
|
+
"",
|
|
378
|
+
"Suggested Commands:",
|
|
379
|
+
` ${inspectCommand}`,
|
|
380
|
+
` ${executeCommand}`,
|
|
381
|
+
"",
|
|
382
|
+
"On-chain UTXOs:",
|
|
383
|
+
utxos ? formatUtxoList(utxos) : " (unavailable: RPC lookup failed)",
|
|
384
|
+
"",
|
|
385
|
+
"Linked Preset:",
|
|
386
|
+
preset ? indent(formatPresetHelp(preset)) : " (none)",
|
|
387
|
+
].join("\n");
|
|
388
|
+
}
|
|
389
|
+
function formatScaffoldBundle(preset) {
|
|
390
|
+
const scaffold = buildScaffoldData(preset);
|
|
391
|
+
return [
|
|
392
|
+
`Scaffold for ${preset.title} (${preset.id})`,
|
|
393
|
+
"",
|
|
394
|
+
"Compile:",
|
|
395
|
+
` ${scaffold.compileCommand}`,
|
|
396
|
+
"",
|
|
397
|
+
"Direct Execute:",
|
|
398
|
+
` ${scaffold.executeCommand}`,
|
|
399
|
+
"",
|
|
400
|
+
"Gasless Execute:",
|
|
401
|
+
` ${scaffold.gaslessCommand}`,
|
|
402
|
+
"",
|
|
403
|
+
"Example Params JSON:",
|
|
404
|
+
indent(scaffold.paramsJson),
|
|
405
|
+
"",
|
|
406
|
+
"Example Witness JSON:",
|
|
407
|
+
indent(scaffold.witnessJson),
|
|
408
|
+
"",
|
|
409
|
+
"Support Files:",
|
|
410
|
+
" - .env.example",
|
|
411
|
+
" - fund.command.txt",
|
|
412
|
+
].join("\n");
|
|
413
|
+
}
|
|
414
|
+
async function main() {
|
|
415
|
+
const command = process.argv[2];
|
|
416
|
+
const subcommand = process.argv[3];
|
|
417
|
+
const sdk = (0, SimplicityClient_1.createSimplicityClient)(resolveConfig());
|
|
418
|
+
if (!command) {
|
|
419
|
+
throw new Error("Usage: simplicity-cli <compile|presets|preset|contract|artifact|gasless> ...");
|
|
420
|
+
}
|
|
421
|
+
if (command === "compile") {
|
|
422
|
+
const result = await sdk.compileFromFile({
|
|
423
|
+
simfPath: requireArg("simf"),
|
|
424
|
+
templateVars: parseAssignments(getMultiArgs("template-var")),
|
|
425
|
+
artifactPath: getArg("artifact"),
|
|
426
|
+
});
|
|
427
|
+
printJson({ artifact: result.artifact, deployment: result.deployment() });
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
if (command === "presets" && subcommand === "list") {
|
|
431
|
+
printJson((0, presets_1.listPresets)().map((preset) => (0, presets_1.describePreset)(preset)));
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
if (command === "presets" && subcommand === "show") {
|
|
435
|
+
const preset = (0, presets_1.getPresetOrThrow)(requireArg("preset"));
|
|
436
|
+
if (hasFlag("json")) {
|
|
437
|
+
printJson((0, presets_1.describePreset)(preset));
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
process.stdout.write(`${formatPresetHelp(preset)}\n`);
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
if (command === "presets" && subcommand === "scaffold") {
|
|
444
|
+
const preset = (0, presets_1.getPresetOrThrow)(requireArg("preset"));
|
|
445
|
+
const scaffold = buildScaffoldData(preset);
|
|
446
|
+
const writeDir = getArg("write-dir");
|
|
447
|
+
if (hasFlag("json")) {
|
|
448
|
+
printJson({
|
|
449
|
+
preset: (0, presets_1.describePreset)(preset),
|
|
450
|
+
compileCommand: scaffold.compileCommand,
|
|
451
|
+
executeCommand: scaffold.executeCommand,
|
|
452
|
+
gaslessCommand: scaffold.gaslessCommand,
|
|
453
|
+
});
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
const writtenFiles = writeDir ? await writeScaffoldFiles(writeDir, preset) : [];
|
|
457
|
+
process.stdout.write(`${formatScaffoldBundle(preset)}\n`);
|
|
458
|
+
if (writtenFiles.length > 0) {
|
|
459
|
+
process.stdout.write(`\nWritten Files:\n${writtenFiles.map((file) => ` ${file}`).join("\n")}\n`);
|
|
460
|
+
}
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
if (command === "preset" && subcommand === "compile") {
|
|
464
|
+
const params = parseAssignments(getMultiArgs("param"));
|
|
465
|
+
if (params.minHeight !== undefined && params.MIN_HEIGHT === undefined)
|
|
466
|
+
params.MIN_HEIGHT = params.minHeight;
|
|
467
|
+
if (params.signerXonly !== undefined && params.SIGNER_XONLY === undefined)
|
|
468
|
+
params.SIGNER_XONLY = params.signerXonly;
|
|
469
|
+
if (params.refundXonly !== undefined && params.REFUND_XONLY === undefined)
|
|
470
|
+
params.REFUND_XONLY = params.refundXonly;
|
|
471
|
+
const result = await sdk.compileFromPreset({
|
|
472
|
+
preset: requireArg("preset"),
|
|
473
|
+
params,
|
|
474
|
+
artifactPath: getArg("artifact"),
|
|
475
|
+
});
|
|
476
|
+
printJson({ artifact: result.artifact, deployment: result.deployment() });
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
if (command === "artifact" && subcommand === "show") {
|
|
480
|
+
const artifact = await (0, artifact_1.loadArtifact)(requireArg("artifact"));
|
|
481
|
+
const preset = artifact.source.mode === "preset" && artifact.source.preset
|
|
482
|
+
? (0, presets_1.getPresetOrThrow)(artifact.source.preset)
|
|
483
|
+
: null;
|
|
484
|
+
let utxos = null;
|
|
485
|
+
try {
|
|
486
|
+
utxos = await sdk.fromArtifact(artifact).findUtxos();
|
|
487
|
+
}
|
|
488
|
+
catch {
|
|
489
|
+
utxos = null;
|
|
490
|
+
}
|
|
491
|
+
if (!hasFlag("json")) {
|
|
492
|
+
process.stdout.write(`${formatArtifactHelp(artifact, preset, utxos)}\n`);
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
printJson({
|
|
496
|
+
artifact,
|
|
497
|
+
preset,
|
|
498
|
+
utxos,
|
|
499
|
+
status: classifyArtifactStatus(utxos),
|
|
500
|
+
ready: classifyArtifactStatus(utxos) === "executable",
|
|
501
|
+
});
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
if (command === "contract" && subcommand === "wait-funding") {
|
|
505
|
+
const compiled = await sdk.loadArtifact(requireArg("artifact"));
|
|
506
|
+
const utxos = await compiled.at().waitForFunding({
|
|
507
|
+
minAmountSat: getArg("min-amount-sat") ? Number(getArg("min-amount-sat")) : undefined,
|
|
508
|
+
pollIntervalMs: getArg("poll-interval-ms") ? Number(getArg("poll-interval-ms")) : undefined,
|
|
509
|
+
timeoutMs: getArg("timeout-ms") ? Number(getArg("timeout-ms")) : undefined,
|
|
510
|
+
});
|
|
511
|
+
printJson(utxos);
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
if (command === "contract" &&
|
|
515
|
+
(subcommand === "inspect" || subcommand === "execute" || subcommand === "execute-gasless")) {
|
|
516
|
+
const compiled = await sdk.loadArtifact(requireArg("artifact"));
|
|
517
|
+
const contract = compiled.at();
|
|
518
|
+
const witnessFile = getArg("witness-file");
|
|
519
|
+
const witness = witnessFile || getMultiArgs("witness-value").length > 0
|
|
520
|
+
? {
|
|
521
|
+
source: witnessFile ? await (0, promises_1.readFile)(witnessFile, "utf8") : undefined,
|
|
522
|
+
values: getMultiArgs("witness-value").length > 0 ? parseWitnessAssignments(getMultiArgs("witness-value")) : undefined,
|
|
523
|
+
signers: getMultiArgs("witness-signer").length > 0 ? parseWitnessSigners(getMultiArgs("witness-signer")) : undefined,
|
|
524
|
+
}
|
|
525
|
+
: getMultiArgs("witness-signer").length > 0
|
|
526
|
+
? {
|
|
527
|
+
signers: parseWitnessSigners(getMultiArgs("witness-signer")),
|
|
528
|
+
}
|
|
529
|
+
: undefined;
|
|
530
|
+
const payload = {
|
|
531
|
+
wallet: getArg("wallet", process.env.ELEMENTS_RPC_WALLET ?? "simplicity-test"),
|
|
532
|
+
toAddress: requireArg("to-address"),
|
|
533
|
+
sendAmount: getArg("send-amount") ? Number(getArg("send-amount")) : undefined,
|
|
534
|
+
feeSat: getArg("fee-sat") ? Number(getArg("fee-sat")) : undefined,
|
|
535
|
+
expectedLiquidReceiver: getArg("expected-liquid-receiver"),
|
|
536
|
+
purpose: getArg("purpose"),
|
|
537
|
+
periodId: getArg("period-id"),
|
|
538
|
+
bondDefinitionId: getArg("bond-definition-id"),
|
|
539
|
+
utxoPolicy: getArg("utxo-policy") ?? undefined,
|
|
540
|
+
signer: {
|
|
541
|
+
type: "schnorrPrivkeyHex",
|
|
542
|
+
privkeyHex: requireArg("privkey"),
|
|
543
|
+
},
|
|
544
|
+
witness,
|
|
545
|
+
broadcast: hasFlag("broadcast"),
|
|
546
|
+
verbose: hasFlag("verbose"),
|
|
547
|
+
};
|
|
548
|
+
if (subcommand === "inspect") {
|
|
549
|
+
const result = await contract.inspectCall(payload);
|
|
550
|
+
printJson(result);
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
if (subcommand === "execute-gasless") {
|
|
554
|
+
const relayerUrl = getArg("relayer");
|
|
555
|
+
const result = await contract.executeGasless({
|
|
556
|
+
wallet: getArg("wallet", process.env.ELEMENTS_RPC_WALLET ?? "simplicity-test"),
|
|
557
|
+
sponsorWallet: relayerUrl ? undefined : requireArg("sponsor-wallet"),
|
|
558
|
+
relayer: relayerUrl
|
|
559
|
+
? sdk.relayer({
|
|
560
|
+
baseUrl: relayerUrl,
|
|
561
|
+
apiKey: requireArg("api-key"),
|
|
562
|
+
})
|
|
563
|
+
: undefined,
|
|
564
|
+
fromLabel: getArg("from-label"),
|
|
565
|
+
toAddress: requireArg("to-address"),
|
|
566
|
+
sendAmount: getArg("send-amount") ? Number(getArg("send-amount")) : undefined,
|
|
567
|
+
feeSat: getArg("fee-sat") ? Number(getArg("fee-sat")) : undefined,
|
|
568
|
+
contractChangeAddress: getArg("contract-change-address"),
|
|
569
|
+
sponsorChangeAddress: getArg("sponsor-change-address"),
|
|
570
|
+
signer: {
|
|
571
|
+
type: "schnorrPrivkeyHex",
|
|
572
|
+
privkeyHex: requireArg("privkey"),
|
|
573
|
+
},
|
|
574
|
+
witness,
|
|
575
|
+
utxoPolicy: getArg("utxo-policy") ?? undefined,
|
|
576
|
+
broadcast: hasFlag("broadcast"),
|
|
577
|
+
});
|
|
578
|
+
printJson(result);
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
const result = await contract.execute(payload);
|
|
582
|
+
printJson(result);
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
if (command === "gasless" && subcommand === "request") {
|
|
586
|
+
const relayer = sdk.relayer({
|
|
587
|
+
baseUrl: requireArg("relayer"),
|
|
588
|
+
apiKey: requireArg("api-key"),
|
|
589
|
+
});
|
|
590
|
+
const result = await relayer.requestPset({
|
|
591
|
+
amount: Number(requireArg("amount")),
|
|
592
|
+
toAddress: requireArg("to-address"),
|
|
593
|
+
fromLabel: requireArg("from-label"),
|
|
594
|
+
});
|
|
595
|
+
printJson(result);
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
if (command === "gasless" && subcommand === "submit") {
|
|
599
|
+
const relayer = sdk.relayer({
|
|
600
|
+
baseUrl: requireArg("relayer"),
|
|
601
|
+
apiKey: requireArg("api-key"),
|
|
602
|
+
});
|
|
603
|
+
const result = await relayer.submitSignedPset({
|
|
604
|
+
psetId: requireArg("pset-id"),
|
|
605
|
+
signedPsetBase64: requireArg("signed-pset"),
|
|
606
|
+
});
|
|
607
|
+
printJson(result);
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
if (command === "gasless" && subcommand === "status") {
|
|
611
|
+
const relayer = sdk.relayer({
|
|
612
|
+
baseUrl: requireArg("relayer"),
|
|
613
|
+
apiKey: requireArg("api-key"),
|
|
614
|
+
});
|
|
615
|
+
const result = await relayer.getPsetStatus(requireArg("pset-id"));
|
|
616
|
+
printJson(result);
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
throw new Error(`Unknown command: ${command}${subcommand ? ` ${subcommand}` : ""}`);
|
|
620
|
+
}
|
|
621
|
+
main().catch((error) => {
|
|
622
|
+
if (error instanceof errors_1.SimplicitySdkError) {
|
|
623
|
+
printJson({ error: { code: error.code, message: error.message, details: error.details } });
|
|
624
|
+
process.exit(1);
|
|
625
|
+
}
|
|
626
|
+
printJson({ error: { code: "UNEXPECTED", message: String(error?.message ?? error) } });
|
|
627
|
+
process.exit(1);
|
|
628
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { DeploymentInfo, SimplicityArtifact, SimplicityClientConfig } from "../core/types";
|
|
2
|
+
import { DeployedContract } from "./DeployedContract";
|
|
3
|
+
export declare class CompiledContract {
|
|
4
|
+
private readonly config;
|
|
5
|
+
readonly artifact: SimplicityArtifact;
|
|
6
|
+
constructor(config: SimplicityClientConfig, artifact: SimplicityArtifact);
|
|
7
|
+
get contractAddress(): string;
|
|
8
|
+
get cmr(): string;
|
|
9
|
+
get program(): string;
|
|
10
|
+
deployment(): DeploymentInfo;
|
|
11
|
+
saveArtifact(path: string): Promise<void>;
|
|
12
|
+
at(addressOverride?: string): DeployedContract;
|
|
13
|
+
}
|