cashscript 0.9.2 → 0.10.0-next.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 (37) hide show
  1. package/dist/{Contract.d.ts → src/Contract.d.ts} +3 -2
  2. package/dist/{Contract.js → src/Contract.js} +1 -0
  3. package/dist/{Errors.d.ts → src/Errors.d.ts} +2 -2
  4. package/dist/{Errors.js → src/Errors.js} +3 -3
  5. package/dist/src/LibauthTemplate.d.ts +12 -0
  6. package/dist/src/LibauthTemplate.js +472 -0
  7. package/dist/{SignatureTemplate.d.ts → src/SignatureTemplate.d.ts} +1 -1
  8. package/dist/{Transaction.d.ts → src/Transaction.d.ts} +9 -7
  9. package/dist/{Transaction.js → src/Transaction.js} +47 -8
  10. package/dist/{index.d.ts → src/index.d.ts} +2 -1
  11. package/dist/{index.js → src/index.js} +2 -1
  12. package/dist/{interfaces.d.ts → src/interfaces.d.ts} +1 -1
  13. package/dist/src/network/MockNetworkProvider.d.ts +14 -0
  14. package/dist/src/network/MockNetworkProvider.js +46 -0
  15. package/dist/{network → src/network}/index.d.ts +1 -0
  16. package/dist/{network → src/network}/index.js +1 -0
  17. package/dist/{utils.d.ts → src/utils.d.ts} +6 -3
  18. package/dist/{utils.js → src/utils.js} +41 -14
  19. package/dist/test/JestExtensions.d.ts +9 -0
  20. package/dist/test/JestExtensions.js +66 -0
  21. package/package.json +8 -6
  22. /package/dist/{Argument.d.ts → src/Argument.d.ts} +0 -0
  23. /package/dist/{Argument.js → src/Argument.js} +0 -0
  24. /package/dist/{SignatureTemplate.js → src/SignatureTemplate.js} +0 -0
  25. /package/dist/{TransactionBuilder.d.ts → src/TransactionBuilder.d.ts} +0 -0
  26. /package/dist/{TransactionBuilder.js → src/TransactionBuilder.js} +0 -0
  27. /package/dist/{constants.d.ts → src/constants.d.ts} +0 -0
  28. /package/dist/{constants.js → src/constants.js} +0 -0
  29. /package/dist/{interfaces.js → src/interfaces.js} +0 -0
  30. /package/dist/{network → src/network}/BitcoinRpcNetworkProvider.d.ts +0 -0
  31. /package/dist/{network → src/network}/BitcoinRpcNetworkProvider.js +0 -0
  32. /package/dist/{network → src/network}/ElectrumNetworkProvider.d.ts +0 -0
  33. /package/dist/{network → src/network}/ElectrumNetworkProvider.js +0 -0
  34. /package/dist/{network → src/network}/FullStackNetworkProvider.d.ts +0 -0
  35. /package/dist/{network → src/network}/FullStackNetworkProvider.js +0 -0
  36. /package/dist/{network → src/network}/NetworkProvider.d.ts +0 -0
  37. /package/dist/{network → src/network}/NetworkProvider.js +0 -0
@@ -4,7 +4,8 @@ import { Argument } from './Argument.js';
4
4
  import { Unlocker, ContractOptions, Utxo } from './interfaces.js';
5
5
  import NetworkProvider from './network/NetworkProvider.js';
6
6
  export declare class Contract {
7
- private artifact;
7
+ artifact: Artifact;
8
+ constructorArgs: Argument[];
8
9
  private options?;
9
10
  name: string;
10
11
  address: string;
@@ -16,7 +17,7 @@ export declare class Contract {
16
17
  unlock: Record<string, ContractUnlocker>;
17
18
  redeemScript: Script;
18
19
  provider: NetworkProvider;
19
- private addressType;
20
+ addressType: 'p2sh20' | 'p2sh32';
20
21
  constructor(artifact: Artifact, constructorArgs: Argument[], options?: ContractOptions | undefined);
21
22
  getBalance(): Promise<bigint>;
22
23
  getUtxos(): Promise<Utxo[]>;
@@ -8,6 +8,7 @@ import { ElectrumNetworkProvider } from './network/index.js';
8
8
  export class Contract {
9
9
  constructor(artifact, constructorArgs, options) {
10
10
  this.artifact = artifact;
11
+ this.constructorArgs = constructorArgs;
11
12
  this.options = options;
12
13
  this.provider = this.options?.provider ?? new ElectrumNetworkProvider();
13
14
  this.addressType = this.options?.addressType ?? 'p2sh32';
@@ -10,8 +10,8 @@ export declare class TokensToNonTokenAddressError extends Error {
10
10
  }
11
11
  export declare class FailedTransactionError extends Error {
12
12
  reason: string;
13
- meep?: string | undefined;
14
- constructor(reason: string, meep?: string | undefined);
13
+ debugStr?: string | undefined;
14
+ constructor(reason: string, debugStr?: string | undefined);
15
15
  }
16
16
  export declare class FailedRequireError extends FailedTransactionError {
17
17
  }
@@ -14,10 +14,10 @@ export class TokensToNonTokenAddressError extends Error {
14
14
  }
15
15
  }
16
16
  export class FailedTransactionError extends Error {
17
- constructor(reason, meep) {
18
- super(`Transaction failed with reason: ${reason}${meep ? `\n${meep}` : ''}`);
17
+ constructor(reason, debugStr) {
18
+ super(`Transaction failed with reason: ${reason}${debugStr ? `\n\n${debugStr}` : ''}`);
19
19
  this.reason = reason;
20
- this.meep = meep;
20
+ this.debugStr = debugStr;
21
21
  }
22
22
  }
23
23
  export class FailedRequireError extends FailedTransactionError {
@@ -0,0 +1,12 @@
1
+ import { Artifact } from '@cashscript/utils';
2
+ import { AuthenticationTemplate, AuthenticationProgramStateBCHCHIPs } from '@bitauth/libauth';
3
+ import { Transaction } from './Transaction.js';
4
+ export declare const stringify: (any: any, spaces?: number | undefined) => string;
5
+ export declare const buildTemplate: ({ transaction, transactionHex, }: {
6
+ transaction: Transaction;
7
+ transactionHex?: string | undefined;
8
+ }) => Promise<AuthenticationTemplate>;
9
+ export declare const getBitauthUri: (template: AuthenticationTemplate) => string;
10
+ export declare const evaluateTemplate: (template: AuthenticationTemplate) => boolean;
11
+ export declare type DebugResult = AuthenticationProgramStateBCHCHIPs[];
12
+ export declare const debugTemplate: (template: AuthenticationTemplate, artifact: Artifact) => DebugResult;
@@ -0,0 +1,472 @@
1
+ import { Op, PrimitiveType, bytecodeToScript, decodeBool, decodeInt, decodeString, formatLibauthScript, } from '@cashscript/utils';
2
+ import { hash160, hexToBin, decodeTransaction, binToHex, authenticationTemplateToCompilerConfiguration, createCompiler, createVirtualMachineBCHCHIPs, binToBase64, utf8ToBin, isHex, AuthenticationErrorCommon, } from '@bitauth/libauth';
3
+ import { deflate } from 'pako';
4
+ import { isUtxoP2PKH, } from '../src/interfaces.js';
5
+ import { encodeArgument as csEncodeArgument } from './Argument.js';
6
+ import { toRegExp } from './utils.js';
7
+ // all bitauth variables must be in snake case
8
+ const snakeCase = (str) => (str
9
+ && str
10
+ .match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
11
+ .map((s) => s.toLowerCase())
12
+ .join('_'));
13
+ const merge = (array) => array.reduce((prev, cur) => ({
14
+ ...prev,
15
+ ...{ [Object.keys(cur)[0]]: cur[Object.keys(cur)[0]] },
16
+ }), {});
17
+ const encodeArgument = (argument, typeStr) => {
18
+ if (typeStr === PrimitiveType.INT && argument === 0n) {
19
+ return Uint8Array.from([0]);
20
+ }
21
+ return csEncodeArgument(argument, typeStr);
22
+ };
23
+ // stringify version which can serialize otherwise unsupported types
24
+ export const stringify = (any, spaces) => JSON.stringify(any, (_, v) => {
25
+ if (typeof v === 'bigint') {
26
+ return `${v.toString()}`;
27
+ }
28
+ if (v instanceof Uint8Array) {
29
+ return `${binToHex(v)}`;
30
+ }
31
+ return v;
32
+ }, spaces);
33
+ const zip = (a, b) => Array.from(Array(Math.max(b.length, a.length)), (_, i) => [a[i], b[i]]);
34
+ const createScenarioTransaction = (libauthTransaction, csTransaction) => {
35
+ const contract = csTransaction.contract;
36
+ const result = {};
37
+ // only one 'slot' is allowed, otherwise {} must be used
38
+ let inputSlotInserted = false;
39
+ result.inputs = libauthTransaction.inputs.map((input, index) => {
40
+ const csInput = csTransaction.inputs[index];
41
+ const signable = isUtxoP2PKH(csInput);
42
+ let unlockingBytecode = {};
43
+ if (signable) {
44
+ unlockingBytecode = {
45
+ script: 'p2pkh_placeholder_unlock',
46
+ overrides: {
47
+ keys: {
48
+ privateKeys: {
49
+ placeholder_key: binToHex(csInput.template.privateKey),
50
+ },
51
+ },
52
+ },
53
+ };
54
+ }
55
+ else {
56
+ // assume it is our contract's input
57
+ // eslint-disable-next-line
58
+ if (!inputSlotInserted) {
59
+ unlockingBytecode = ['slot'];
60
+ inputSlotInserted = true;
61
+ }
62
+ }
63
+ return {
64
+ outpointIndex: input.outpointIndex,
65
+ outpointTransactionHash: input.outpointTransactionHash instanceof Uint8Array
66
+ ? binToHex(input.outpointTransactionHash)
67
+ : input.outpointTransactionHash,
68
+ sequenceNumber: input.sequenceNumber,
69
+ unlockingBytecode,
70
+ };
71
+ });
72
+ result.locktime = libauthTransaction.locktime;
73
+ result.outputs = libauthTransaction.outputs.map((output, index) => {
74
+ const csOutput = csTransaction.outputs[index];
75
+ let { lockingBytecode } = output;
76
+ if (typeof csOutput.to === 'string') {
77
+ if ([
78
+ contract.address,
79
+ contract.tokenAddress,
80
+ ].includes(csOutput.to)) {
81
+ lockingBytecode = {};
82
+ }
83
+ else {
84
+ for (const csInput of csTransaction.inputs) {
85
+ if (isUtxoP2PKH(csInput)) {
86
+ const inputPkh = hash160(csInput.template.getPublicKey());
87
+ if (binToHex(output.lockingBytecode).slice(6, 46)
88
+ === binToHex(inputPkh)) {
89
+ lockingBytecode = {
90
+ script: 'p2pkh_placeholder_lock',
91
+ overrides: {
92
+ keys: {
93
+ privateKeys: {
94
+ placeholder_key: binToHex(csInput.template.privateKey),
95
+ },
96
+ },
97
+ },
98
+ };
99
+ }
100
+ }
101
+ }
102
+ }
103
+ }
104
+ return {
105
+ lockingBytecode: lockingBytecode instanceof Uint8Array
106
+ ? binToHex(lockingBytecode)
107
+ : lockingBytecode,
108
+ token: output.token,
109
+ valueSatoshis: Number(output.valueSatoshis),
110
+ };
111
+ });
112
+ result.version = libauthTransaction.version;
113
+ return result;
114
+ };
115
+ const createScenarioSourceOutputs = (csTransaction) => {
116
+ // only one 'slot' is allowed, otherwise {} must be used
117
+ let inputSlotInserted = false;
118
+ return csTransaction.inputs.map((csInput) => {
119
+ const signable = isUtxoP2PKH(csInput);
120
+ let lockingBytecode = {};
121
+ if (signable) {
122
+ lockingBytecode = {
123
+ script: 'p2pkh_placeholder_lock',
124
+ overrides: {
125
+ keys: {
126
+ privateKeys: {
127
+ placeholder_key: binToHex(csInput.template.privateKey),
128
+ },
129
+ },
130
+ },
131
+ };
132
+ }
133
+ else {
134
+ // assume it is our contract's input
135
+ // eslint-disable-next-line
136
+ if (!inputSlotInserted) {
137
+ lockingBytecode = ['slot'];
138
+ inputSlotInserted = true;
139
+ }
140
+ }
141
+ const result = {
142
+ lockingBytecode: lockingBytecode,
143
+ valueSatoshis: Number(csInput.satoshis),
144
+ };
145
+ if (csInput.token) {
146
+ result.token = {
147
+ amount: csInput.token.amount.toString(),
148
+ category: csInput.token.category,
149
+ };
150
+ if (csInput.token.nft) {
151
+ result.token.nft = {
152
+ capability: csInput.token.nft.capability,
153
+ commitment: csInput.token.nft.commitment
154
+ };
155
+ }
156
+ }
157
+ return result;
158
+ });
159
+ };
160
+ export const buildTemplate = async ({ transaction, transactionHex = undefined, // set this argument to prevent unnecessary call `transaction.build()`
161
+ }) => {
162
+ const contract = transaction.contract;
163
+ const txHex = transactionHex ?? await transaction.build();
164
+ const libauthTransaction = decodeTransaction(hexToBin(txHex));
165
+ if (typeof libauthTransaction === 'string') {
166
+ throw Error(libauthTransaction);
167
+ }
168
+ const constructorInputs = contract.artifact.constructorInputs
169
+ .slice()
170
+ .reverse();
171
+ const contractParameters = contract.constructorArgs.slice().reverse();
172
+ const abiFunction = transaction.abiFunction;
173
+ const funcName = abiFunction.name;
174
+ const functionIndex = contract.artifact.abi.findIndex((func) => func.name === funcName);
175
+ const func = contract.artifact.abi[functionIndex];
176
+ const functionInputs = func.inputs.slice().reverse();
177
+ const args = transaction.args.slice().reverse();
178
+ const hasSignatureTemplates = transaction.inputs.filter((input) => isUtxoP2PKH(input)).length;
179
+ const formattedBytecode = contract.artifact.debug
180
+ ? formatLibauthScript(bytecodeToScript(hexToBin(contract.artifact.debug.bytecode)), contract.artifact.debug.sourceMap, contract.artifact.source).split('\n')
181
+ : contract.artifact.bytecode.split(' ').map((asmElement) => {
182
+ if (isHex(asmElement)) {
183
+ return `<0x${asmElement}>`;
184
+ }
185
+ return asmElement;
186
+ });
187
+ const template = {
188
+ $schema: 'https://ide.bitauth.com/authentication-template-v0.schema.json',
189
+ description: `Imported from cashscript`,
190
+ name: contract.artifact.contractName,
191
+ supported: ['BCH_SPEC'],
192
+ version: 0,
193
+ };
194
+ // declaration of template variables and their types
195
+ template.entities = {
196
+ parameters: {
197
+ description: 'Contract creation and function parameters',
198
+ name: 'parameters',
199
+ scripts: [
200
+ 'lock',
201
+ 'unlock_lock',
202
+ ],
203
+ variables: merge([
204
+ ...functionInputs.map((input) => ({
205
+ [snakeCase(input.name)]: {
206
+ description: `"${input.name}" parameter of function "${func.name}"`,
207
+ name: input.name,
208
+ type: input.type === PrimitiveType.SIG ? 'Key' : 'WalletData',
209
+ },
210
+ })),
211
+ {
212
+ function_index: {
213
+ description: 'Script function index to execute',
214
+ name: 'function_index',
215
+ type: 'WalletData',
216
+ },
217
+ },
218
+ ...constructorInputs.map((input) => ({
219
+ [snakeCase(input.name)]: {
220
+ description: `"${input.name}" parameter of this contract`,
221
+ name: input.name,
222
+ type: 'WalletData',
223
+ },
224
+ })),
225
+ ]),
226
+ }
227
+ };
228
+ // add extra variables for the p2pkh utxos spent together with our contract
229
+ if (hasSignatureTemplates) {
230
+ template.entities.parameters.scripts.push('p2pkh_placeholder_lock', 'p2pkh_placeholder_unlock');
231
+ template.entities.parameters.variables = {
232
+ ...template.entities.parameters.variables,
233
+ placeholder_key: {
234
+ description: 'placeholder_key',
235
+ name: 'placeholder_key',
236
+ type: 'Key',
237
+ },
238
+ };
239
+ }
240
+ template.scenarios = {
241
+ // single scenario to spend out transaction under test given the CashScript parameters provided
242
+ evaluate_function: {
243
+ name: 'Evaluate',
244
+ description: 'An example evaluation where this script execution passes.',
245
+ data: {
246
+ // encode values for the variables defined above in `entities` property
247
+ bytecode: merge([
248
+ ...zip(functionInputs, args)
249
+ .filter(([input]) => input.type !== PrimitiveType.SIG)
250
+ .map(([input, arg]) => {
251
+ const hex = binToHex(arg);
252
+ const result = hex.length ? `0x${hex}` : hex;
253
+ return {
254
+ [snakeCase(input.name)]: result,
255
+ };
256
+ }),
257
+ { function_index: functionIndex.toString() },
258
+ ...constructorInputs.map((input, index) => {
259
+ const hex = binToHex(encodeArgument(contractParameters[index], constructorInputs[index].type));
260
+ const result = hex.length ? `0x${hex}` : hex;
261
+ return {
262
+ [snakeCase(input.name)]: result,
263
+ };
264
+ }),
265
+ ]),
266
+ currentBlockHeight: 2,
267
+ currentBlockTime: Math.round(+new Date() / 1000),
268
+ keys: {
269
+ privateKeys: merge([
270
+ ...zip(functionInputs, args)
271
+ .filter(([input]) => input.type === PrimitiveType.SIG)
272
+ .map(([input, arg]) => ({
273
+ [snakeCase(input.name)]: binToHex(arg.privateKey),
274
+ })),
275
+ ...(hasSignatureTemplates
276
+ ? [
277
+ {
278
+ // placeholder will be replaced by a key for each respective P2PKH input spent
279
+ placeholder_key: '<Uint8Array: 0x0000000000000000000000000000000000000000000000000000000000000000>',
280
+ },
281
+ ]
282
+ : []),
283
+ ]),
284
+ },
285
+ },
286
+ transaction: createScenarioTransaction(libauthTransaction, transaction),
287
+ sourceOutputs: createScenarioSourceOutputs(transaction),
288
+ },
289
+ };
290
+ // definition of locking scripts and unlocking scripts with their respective bytecode
291
+ template.scripts = {
292
+ unlock_lock: {
293
+ // this unlocking script must pass our only scenario
294
+ passes: ['evaluate_function'],
295
+ name: 'unlock',
296
+ // unlocking script contains the CashScript function parameters and function selector
297
+ // we output these values as pushdata, comment will contain the type and the value of the variable
298
+ // example: '<timeout> // int = <0xa08601>'
299
+ script: [
300
+ `// "${func.name}" function parameters`,
301
+ ...(functionInputs.length
302
+ ? zip(functionInputs, args).map(([input, arg]) => (input.type === PrimitiveType.SIG
303
+ ? `<${snakeCase(input.name)}.schnorr_signature.all_outputs> // ${input.type}`
304
+ : `<${snakeCase(input.name)}> // ${input.type} = <${`0x${binToHex(arg)}`}>`))
305
+ : ['// none']),
306
+ '',
307
+ ...(contract.artifact.abi.length > 1
308
+ ? [
309
+ '// function index in contract',
310
+ `<function_index> // int = <${functionIndex.toString()}>`,
311
+ '',
312
+ ]
313
+ : []),
314
+ ].join('\n'),
315
+ unlocks: 'lock',
316
+ },
317
+ lock: {
318
+ lockingType: "p2sh20",
319
+ name: 'lock',
320
+ // locking script contains the CashScript contract parameters followed by the contract opcodes
321
+ // we output these values as pushdata, comment will contain the type and the value of the variable
322
+ // example: '<timeout> // int = <0xa08601>'
323
+ script: [
324
+ `// "${contract.artifact.contractName}" contract constructor parameters`,
325
+ ...(constructorInputs.length
326
+ ? constructorInputs.map((input, index) => {
327
+ const encoded = encodeArgument(contractParameters[index], constructorInputs[index].type);
328
+ return `<${snakeCase(input.name)}> // ${input.type === 'bytes' ? `bytes${encoded.length}` : input.type} = <${`0x${binToHex(encoded)}`}>`;
329
+ })
330
+ : ['// none']),
331
+ '',
332
+ '// bytecode',
333
+ ...formattedBytecode,
334
+ ].join('\n'),
335
+ },
336
+ };
337
+ // add extra unlocking and locking script for P2PKH inputs spent alongside our contract
338
+ // this is needed for correct cross-referrences in the template
339
+ if (hasSignatureTemplates) {
340
+ template.scripts.p2pkh_placeholder_unlock = {
341
+ name: 'p2pkh_placeholder_unlock',
342
+ script: '<placeholder_key.schnorr_signature.all_outputs>\n<placeholder_key.public_key>',
343
+ unlocks: 'p2pkh_placeholder_lock',
344
+ };
345
+ template.scripts.p2pkh_placeholder_lock = {
346
+ lockingType: 'standard',
347
+ name: 'p2pkh_placeholder_lock',
348
+ script: 'OP_DUP\nOP_HASH160 <$(<placeholder_key.public_key> OP_HASH160\n)> OP_EQUALVERIFY\nOP_CHECKSIG',
349
+ };
350
+ }
351
+ return template;
352
+ };
353
+ export const getBitauthUri = (template) => {
354
+ const base64toBase64Url = (base64) => base64.replace(/\+/g, '-').replace(/\//g, '_');
355
+ const payload = base64toBase64Url(binToBase64(deflate(utf8ToBin(stringify(template)))));
356
+ return `https://ide.bitauth.com/import-template/${payload}`;
357
+ };
358
+ // internal util. instantiates the virtual machine and compiles the template into a program
359
+ const createProgram = (template) => {
360
+ const configuration = authenticationTemplateToCompilerConfiguration(template);
361
+ const vm = createVirtualMachineBCHCHIPs();
362
+ const compiler = createCompiler(configuration);
363
+ const scenarioGeneration = compiler.generateScenario({
364
+ debug: true,
365
+ lockingScriptId: undefined,
366
+ unlockingScriptId: 'unlock_lock',
367
+ scenarioId: 'evaluate_function',
368
+ });
369
+ if (typeof scenarioGeneration === 'string'
370
+ || typeof scenarioGeneration.scenario === 'string') {
371
+ // eslint-disable-next-line
372
+ throw scenarioGeneration;
373
+ }
374
+ return { vm, program: scenarioGeneration.scenario.program };
375
+ };
376
+ // evaluates the fully defined template, throws upon error
377
+ export const evaluateTemplate = (template) => {
378
+ const { vm, program } = createProgram(template);
379
+ const verifyResult = vm.verify(program);
380
+ if (typeof verifyResult === 'string') {
381
+ // eslint-disable-next-line
382
+ throw verifyResult;
383
+ }
384
+ return verifyResult;
385
+ };
386
+ // debugs the template, optionally logging the execution data
387
+ export const debugTemplate = (template, artifact) => {
388
+ const { vm, program } = createProgram(template);
389
+ const debugResult = vm.debug(program);
390
+ for (const log of artifact.debug?.logs ?? []) {
391
+ // there might be 2 elements with same instruction pointer, first from unllocking script, second from locking
392
+ const state = debugResult
393
+ .filter((debugState) => debugState.ip === log.ip)
394
+ .slice().reverse()[0];
395
+ if (!state) {
396
+ throw Error(`Instruction pointer ${log.ip} points to a non-existing state of the program`);
397
+ }
398
+ let line = `${artifact.contractName}.cash:${log.line}`;
399
+ log.data.forEach((element) => {
400
+ let value;
401
+ if (typeof element === 'string') {
402
+ value = element;
403
+ }
404
+ else {
405
+ const stackItem = state.stack.slice().reverse()[element.stackIndex];
406
+ if (!stackItem) {
407
+ throw Error(`Stack item at index ${element.stackIndex} not found at instruction pointer ${log.ip}`);
408
+ }
409
+ switch (element.type) {
410
+ case PrimitiveType.BOOL:
411
+ value = decodeBool(stackItem);
412
+ break;
413
+ case PrimitiveType.INT:
414
+ value = decodeInt(stackItem);
415
+ break;
416
+ case PrimitiveType.STRING:
417
+ value = decodeString(stackItem);
418
+ break;
419
+ default:
420
+ value = `0x${binToHex(stackItem)}`;
421
+ break;
422
+ }
423
+ }
424
+ line += ` ${value}`;
425
+ });
426
+ // actual log, do not delete :)
427
+ console.log(line);
428
+ }
429
+ const lastState = debugResult[debugResult.length - 1];
430
+ if (lastState.error) {
431
+ const requireMessage = (artifact.debug?.requireMessages ?? []).filter((message) => message.ip === lastState.ip)[0];
432
+ if (requireMessage) {
433
+ // eslint-disable-next-line
434
+ throw `${artifact.contractName}.cash:${requireMessage.line} Error in evaluating input index ${lastState.program.inputIndex} with the following message: ${requireMessage.message}.
435
+ ${lastState.error}`;
436
+ }
437
+ else {
438
+ // eslint-disable-next-line
439
+ throw `Error in evaluating input index ${lastState.program.inputIndex}.
440
+ ${lastState.error}`;
441
+ }
442
+ }
443
+ else {
444
+ // one last pass of verifications not covered by the above debugging
445
+ // checks for removed final verify
446
+ const evaluationResult = vm.verify(program);
447
+ if (typeof evaluationResult === 'string' && toRegExp([
448
+ AuthenticationErrorCommon.requiresCleanStack,
449
+ AuthenticationErrorCommon.nonEmptyControlStack,
450
+ AuthenticationErrorCommon.unsuccessfulEvaluation,
451
+ ]).test(evaluationResult)) {
452
+ const stackContents = lastState.stack.map(item => `0x${binToHex(item)}`).join(', ');
453
+ const stackContentsMessage = `\nStack contents after evaluation: ${lastState.stack.length ? stackContents : 'empty'}`;
454
+ const lastMessage = artifact.debug?.requireMessages.sort((a, b) => b.ip - a.ip)[0];
455
+ if (!lastMessage) {
456
+ // eslint-disable-next-line
457
+ throw evaluationResult + stackContentsMessage;
458
+ }
459
+ const instructionsLeft = lastState.instructions.slice(lastMessage.ip);
460
+ if (instructionsLeft.length === 0
461
+ || instructionsLeft.every(instruction => [Op.OP_NIP, Op.OP_ENDIF].includes(instruction.opcode))) {
462
+ // eslint-disable-next-line
463
+ throw `${artifact.contractName}.cash:${lastMessage.line} Error in evaluating input index ${lastState.program.inputIndex} with the following message: ${lastMessage.message}.
464
+ ${evaluationResult.replace(/Error in evaluating input index \d: /, '')}` + stackContentsMessage;
465
+ }
466
+ // eslint-disable-next-line
467
+ throw evaluationResult + stackContentsMessage;
468
+ }
469
+ }
470
+ return debugResult;
471
+ };
472
+ //# sourceMappingURL=LibauthTemplate.js.map
@@ -2,7 +2,7 @@ import { Unlocker, HashType, SignatureAlgorithm } from './interfaces.js';
2
2
  export default class SignatureTemplate {
3
3
  private hashtype;
4
4
  private signatureAlgorithm;
5
- private privateKey;
5
+ privateKey: Uint8Array;
6
6
  constructor(signer: Keypair | Uint8Array | string, hashtype?: HashType, signatureAlgorithm?: SignatureAlgorithm);
7
7
  generateSignature(payload: Uint8Array, bchForkId?: boolean): Uint8Array;
8
8
  getHashType(bchForkId?: boolean): number;
@@ -1,15 +1,16 @@
1
1
  import { AbiFunction } from '@cashscript/utils';
2
- import { Utxo, Recipient, TokenDetails, TransactionDetails, Unlocker } from './interfaces.js';
2
+ import { Utxo, Output, Recipient, TokenDetails, TransactionDetails, Unlocker } from './interfaces.js';
3
3
  import SignatureTemplate from './SignatureTemplate.js';
4
4
  import { Contract } from './Contract.js';
5
+ import { DebugResult } from './LibauthTemplate.js';
5
6
  export declare class Transaction {
6
- private contract;
7
+ contract: Contract;
7
8
  private unlocker;
8
- private abiFunction;
9
- private args;
9
+ abiFunction: AbiFunction;
10
+ args: (Uint8Array | SignatureTemplate)[];
10
11
  private selector?;
11
- private inputs;
12
- private outputs;
12
+ inputs: Utxo[];
13
+ outputs: Output[];
13
14
  private sequence;
14
15
  private locktime;
15
16
  private feePerByte;
@@ -34,7 +35,8 @@ export declare class Transaction {
34
35
  build(): Promise<string>;
35
36
  send(): Promise<TransactionDetails>;
36
37
  send(raw: true): Promise<string>;
38
+ debug(): Promise<DebugResult>;
39
+ bitauthUri(): Promise<string>;
37
40
  private getTxDetails;
38
- meep(): Promise<string>;
39
41
  private setInputsAndOutputs;
40
42
  }
@@ -4,10 +4,12 @@ import delay from 'delay';
4
4
  import { placeholder, scriptToBytecode, } from '@cashscript/utils';
5
5
  import deepEqual from 'fast-deep-equal';
6
6
  import { isUtxoP2PKH, } from './interfaces.js';
7
- import { meep, createInputScript, getInputSize, createOpReturnOutput, getTxSizeWithoutInputs, getPreimageSize, buildError, validateOutput, utxoComparator, calculateDust, getOutputSize, utxoTokenComparator, } from './utils.js';
7
+ import { createInputScript, getInputSize, createOpReturnOutput, getTxSizeWithoutInputs, getPreimageSize, buildError, validateOutput, utxoComparator, calculateDust, getOutputSize, utxoTokenComparator, } from './utils.js';
8
8
  import SignatureTemplate from './SignatureTemplate.js';
9
9
  import { P2PKH_INPUT_SIZE } from './constants.js';
10
10
  import { TransactionBuilder } from './TransactionBuilder.js';
11
+ import MockNetworkProvider from './network/MockNetworkProvider.js';
12
+ import { buildTemplate, debugTemplate, evaluateTemplate, getBitauthUri, } from './LibauthTemplate.js';
11
13
  export class Transaction {
12
14
  constructor(contract, unlocker, abiFunction, args, selector) {
13
15
  this.contract = contract;
@@ -98,15 +100,56 @@ export class Transaction {
98
100
  }
99
101
  async send(raw) {
100
102
  const tx = await this.build();
103
+ let template;
101
104
  try {
105
+ if (this.contract.provider instanceof MockNetworkProvider) {
106
+ template = await buildTemplate({
107
+ transaction: this,
108
+ transactionHex: tx,
109
+ });
110
+ evaluateTemplate(template);
111
+ }
102
112
  const txid = await this.contract.provider.sendRawTransaction(tx);
103
113
  return raw ? await this.getTxDetails(txid, raw) : await this.getTxDetails(txid);
104
114
  }
105
- catch (e) {
106
- const reason = e.error ?? e.message;
107
- throw buildError(reason, meep(tx, this.inputs, this.contract.redeemScript));
115
+ catch (maybeNodeError) {
116
+ if (!template) {
117
+ template = await buildTemplate({
118
+ transaction: this,
119
+ transactionHex: tx,
120
+ });
121
+ }
122
+ const reason = maybeNodeError.error ?? maybeNodeError.message ?? maybeNodeError;
123
+ const bitauthUri = getBitauthUri(template);
124
+ try {
125
+ debugTemplate(template, this.contract.artifact);
126
+ }
127
+ catch (libauthError) {
128
+ if (this.contract.provider instanceof MockNetworkProvider) {
129
+ throw buildError(libauthError, bitauthUri);
130
+ }
131
+ else {
132
+ const message = `${libauthError}\n\nUnderlying node error: ${reason}`;
133
+ throw buildError(message, bitauthUri);
134
+ }
135
+ }
136
+ // this must be unreachable
137
+ throw buildError(reason, bitauthUri);
108
138
  }
109
139
  }
140
+ // method to debug the transaction with libauth VM, throws upon evaluation error
141
+ async debug() {
142
+ const template = await buildTemplate({
143
+ transaction: this,
144
+ });
145
+ return debugTemplate(template, this.contract.artifact);
146
+ }
147
+ async bitauthUri() {
148
+ const template = await buildTemplate({
149
+ transaction: this,
150
+ });
151
+ return getBitauthUri(template);
152
+ }
110
153
  async getTxDetails(txid, raw) {
111
154
  for (let retries = 0; retries < 1200; retries += 1) {
112
155
  await delay(500);
@@ -124,10 +167,6 @@ export class Transaction {
124
167
  // Should not happen
125
168
  throw new Error('Could not retrieve transaction details for over 10 minutes');
126
169
  }
127
- async meep() {
128
- const tx = await this.build();
129
- return meep(tx, this.inputs, this.contract.redeemScript);
130
- }
131
170
  async setInputsAndOutputs() {
132
171
  if (this.outputs.length === 0) {
133
172
  throw Error('Attempted to build a transaction without outputs');
@@ -8,4 +8,5 @@ export { Artifact, AbiFunction, AbiInput } from '@cashscript/utils';
8
8
  export * as utils from '@cashscript/utils';
9
9
  export * from './interfaces.js';
10
10
  export * from './Errors.js';
11
- export { NetworkProvider, BitcoinRpcNetworkProvider, ElectrumNetworkProvider, FullStackNetworkProvider, } from './network/index.js';
11
+ export { NetworkProvider, BitcoinRpcNetworkProvider, ElectrumNetworkProvider, FullStackNetworkProvider, MockNetworkProvider, } from './network/index.js';
12
+ export { randomUtxo, randomToken, randomNFT } from './utils.js';
@@ -7,5 +7,6 @@ export { encodeArgument } from './Argument.js';
7
7
  export * as utils from '@cashscript/utils';
8
8
  export * from './interfaces.js';
9
9
  export * from './Errors.js';
10
- export { BitcoinRpcNetworkProvider, ElectrumNetworkProvider, FullStackNetworkProvider, } from './network/index.js';
10
+ export { BitcoinRpcNetworkProvider, ElectrumNetworkProvider, FullStackNetworkProvider, MockNetworkProvider, } from './network/index.js';
11
+ export { randomUtxo, randomToken, randomNFT } from './utils.js';
11
12
  //# sourceMappingURL=index.js.map
@@ -1,4 +1,4 @@
1
- import type { Transaction } from '@bitauth/libauth';
1
+ import { type Transaction } from '@bitauth/libauth';
2
2
  import type { NetworkProvider } from './network/index.js';
3
3
  import type SignatureTemplate from './SignatureTemplate.js';
4
4
  export interface Utxo {
@@ -0,0 +1,14 @@
1
+ import { Utxo, Network } from '../interfaces.js';
2
+ import NetworkProvider from './NetworkProvider.js';
3
+ export default class MockNetworkProvider implements NetworkProvider {
4
+ private utxoMap;
5
+ private transactionMap;
6
+ network: Network;
7
+ constructor();
8
+ getUtxos(address: string): Promise<Utxo[]>;
9
+ getBlockHeight(): Promise<number>;
10
+ getRawTransaction(txid: string): Promise<string>;
11
+ sendRawTransaction(txHex: string): Promise<string>;
12
+ addUtxo(address: string, utxo: Utxo): void;
13
+ reset(): void;
14
+ }
@@ -0,0 +1,46 @@
1
+ import { binToHex, hexToBin } from '@bitauth/libauth';
2
+ import { sha256 } from '@cashscript/utils';
3
+ import { Network } from '../interfaces.js';
4
+ import { randomUtxo } from '../utils.js';
5
+ // redeclare the addresses from vars.ts instead of importing them
6
+ const aliceAddress = 'bchtest:qpgjmwev3spwlwkgmyjrr2s2cvlkkzlewq62mzgjnp';
7
+ const bobAddress = 'bchtest:qz6q5gqnxdldkr07xpls5474mmzmlesd6qnux4skuc';
8
+ const carolAddress = 'bchtest:qqsr7nqwe6rq5crj63gy5gdqchpnwmguusmr7tfmsj';
9
+ export default class MockNetworkProvider {
10
+ constructor() {
11
+ this.utxoMap = {};
12
+ this.transactionMap = {};
13
+ this.network = Network.CHIPNET;
14
+ for (let i = 0; i < 3; i += 1) {
15
+ this.addUtxo(aliceAddress, randomUtxo());
16
+ this.addUtxo(bobAddress, randomUtxo());
17
+ this.addUtxo(carolAddress, randomUtxo());
18
+ }
19
+ }
20
+ async getUtxos(address) {
21
+ return this.utxoMap[address];
22
+ }
23
+ async getBlockHeight() {
24
+ return 133700;
25
+ }
26
+ async getRawTransaction(txid) {
27
+ return this.transactionMap[txid];
28
+ }
29
+ async sendRawTransaction(txHex) {
30
+ const transactionBin = hexToBin(txHex);
31
+ const txid = binToHex(sha256(sha256(transactionBin)).reverse());
32
+ this.transactionMap[txid] = txHex;
33
+ return txid;
34
+ }
35
+ addUtxo(address, utxo) {
36
+ if (!this.utxoMap[address]) {
37
+ this.utxoMap[address] = [];
38
+ }
39
+ this.utxoMap[address].push(utxo);
40
+ }
41
+ reset() {
42
+ this.utxoMap = {};
43
+ this.transactionMap = {};
44
+ }
45
+ }
46
+ //# sourceMappingURL=MockNetworkProvider.js.map
@@ -2,3 +2,4 @@ export { default as NetworkProvider } from './NetworkProvider.js';
2
2
  export { default as BitcoinRpcNetworkProvider } from './BitcoinRpcNetworkProvider.js';
3
3
  export { default as ElectrumNetworkProvider } from './ElectrumNetworkProvider.js';
4
4
  export { default as FullStackNetworkProvider } from './FullStackNetworkProvider.js';
5
+ export { default as MockNetworkProvider } from './MockNetworkProvider.js';
@@ -1,4 +1,5 @@
1
1
  export { default as BitcoinRpcNetworkProvider } from './BitcoinRpcNetworkProvider.js';
2
2
  export { default as ElectrumNetworkProvider } from './ElectrumNetworkProvider.js';
3
3
  export { default as FullStackNetworkProvider } from './FullStackNetworkProvider.js';
4
+ export { default as MockNetworkProvider } from './MockNetworkProvider.js';
4
5
  //# sourceMappingURL=index.js.map
@@ -1,6 +1,6 @@
1
1
  import { Transaction } from '@bitauth/libauth';
2
2
  import { Script } from '@cashscript/utils';
3
- import { Utxo, Output, LibauthOutput } from './interfaces.js';
3
+ import { Utxo, Output, LibauthOutput, TokenDetails } from './interfaces.js';
4
4
  import { FailedTransactionError } from './Errors.js';
5
5
  export declare function validateOutput(output: Output): void;
6
6
  export declare function calculateDust(output: Output): number;
@@ -14,8 +14,8 @@ export declare function getTxSizeWithoutInputs(outputs: Output[]): number;
14
14
  export declare function createInputScript(redeemScript: Script, encodedArgs: Uint8Array[], selector?: number, preimage?: Uint8Array): Uint8Array;
15
15
  export declare function createOpReturnOutput(opReturnData: string[]): Output;
16
16
  export declare function createSighashPreimage(transaction: Transaction, sourceOutputs: LibauthOutput[], inputIndex: number, coveredBytecode: Uint8Array, hashtype: number): Uint8Array;
17
- export declare function buildError(reason: string, meepStr?: string): FailedTransactionError;
18
- export declare function meep(tx: any, utxos: Utxo[], script: Script): string;
17
+ export declare function buildError(reason: string, debugStr?: string): FailedTransactionError;
18
+ export declare function toRegExp(reasons: string[]): RegExp;
19
19
  export declare function scriptToAddress(script: Script, network: string, addressType: 'p2sh20' | 'p2sh32', tokenSupport: boolean): string;
20
20
  export declare function scriptToLockingBytecode(script: Script, addressType: 'p2sh20' | 'p2sh32'): Uint8Array;
21
21
  export declare function publicKeyToP2PKHLockingBytecode(publicKey: Uint8Array): Uint8Array;
@@ -30,3 +30,6 @@ export declare function utxoTokenComparator(a: Utxo, b: Utxo): number;
30
30
  */
31
31
  export declare function addressToLockScript(address: string): Uint8Array;
32
32
  export declare function getNetworkPrefix(network: string): 'bitcoincash' | 'bchtest' | 'bchreg';
33
+ export declare const randomUtxo: (defaults?: Partial<Utxo> | undefined) => Utxo;
34
+ export declare const randomToken: (defaults?: Partial<TokenDetails> | undefined) => TokenDetails;
35
+ export declare const randomNFT: (defaults?: Partial<TokenDetails> | undefined) => TokenDetails;
@@ -1,5 +1,5 @@
1
- import { cashAddressToLockingBytecode, decodeCashAddress, addressContentsToLockingBytecode, lockingBytecodeToCashAddress, binToHex, generateSigningSerializationBCH, utf8ToBin, hexToBin, flattenBinArray, LockingBytecodeType, encodeTransactionOutput, isHex, bigIntToCompactSize, } from '@bitauth/libauth';
2
- import { encodeInt, hash160, hash256, Op, scriptToBytecode, } from '@cashscript/utils';
1
+ import { cashAddressToLockingBytecode, decodeCashAddress, addressContentsToLockingBytecode, lockingBytecodeToCashAddress, binToHex, generateSigningSerializationBCH, utf8ToBin, hexToBin, flattenBinArray, LockingBytecodeType, encodeTransactionOutput, isHex, bigIntToCompactSize, AuthenticationErrorCommon, NonFungibleTokenCapability, bigIntToVmNumber, } from '@bitauth/libauth';
2
+ import { encodeInt, hash160, hash256, sha256, Op, scriptToBytecode, } from '@cashscript/utils';
3
3
  import { Network, } from './interfaces.js';
4
4
  import { VERSION_SIZE, LOCKTIME_SIZE } from './constants.js';
5
5
  import { OutputSatoshisTooSmallError, TokensToNonTokenAddressError, Reason, FailedTransactionError, FailedRequireError, FailedTimeCheckError, FailedSigCheckError, } from './Errors.js';
@@ -135,35 +135,35 @@ export function createSighashPreimage(transaction, sourceOutputs, inputIndex, co
135
135
  const sighashPreimage = generateSigningSerializationBCH(context, { coveredBytecode, signingSerializationType });
136
136
  return sighashPreimage;
137
137
  }
138
- export function buildError(reason, meepStr) {
138
+ export function buildError(reason, debugStr) {
139
139
  const require = [
140
140
  Reason.EVAL_FALSE, Reason.VERIFY, Reason.EQUALVERIFY, Reason.CHECKMULTISIGVERIFY,
141
141
  Reason.CHECKSIGVERIFY, Reason.CHECKDATASIGVERIFY, Reason.NUMEQUALVERIFY,
142
+ AuthenticationErrorCommon.failedVerify,
143
+ ];
144
+ const timeCheck = [
145
+ Reason.NEGATIVE_LOCKTIME, Reason.UNSATISFIED_LOCKTIME,
146
+ AuthenticationErrorCommon.negativeLocktime, AuthenticationErrorCommon.unsatisfiedLocktime,
142
147
  ];
143
- const timeCheck = [Reason.NEGATIVE_LOCKTIME, Reason.UNSATISFIED_LOCKTIME];
144
148
  const sigCheck = [
145
149
  Reason.SIG_COUNT, Reason.PUBKEY_COUNT, Reason.SIG_HASHTYPE, Reason.SIG_DER,
146
150
  Reason.SIG_HIGH_S, Reason.SIG_NULLFAIL, Reason.SIG_BADLENGTH, Reason.SIG_NONSCHNORR,
151
+ AuthenticationErrorCommon.nonNullSignatureFailure,
147
152
  ];
148
153
  if (toRegExp(require).test(reason)) {
149
- return new FailedRequireError(reason, meepStr);
154
+ return new FailedRequireError(reason, debugStr);
150
155
  }
151
156
  if (toRegExp(timeCheck).test(reason)) {
152
- return new FailedTimeCheckError(reason, meepStr);
157
+ return new FailedTimeCheckError(reason, debugStr);
153
158
  }
154
159
  if (toRegExp(sigCheck).test(reason)) {
155
- return new FailedSigCheckError(reason, meepStr);
160
+ return new FailedSigCheckError(reason, debugStr);
156
161
  }
157
- return new FailedTransactionError(reason, meepStr);
162
+ return new FailedTransactionError(reason, debugStr);
158
163
  }
159
- function toRegExp(reasons) {
164
+ export function toRegExp(reasons) {
160
165
  return new RegExp(reasons.join('|').replace(/\(/g, '\\(').replace(/\)/g, '\\)'));
161
166
  }
162
- // ////////// MISC ////////////////////////////////////////////////////////////
163
- export function meep(tx, utxos, script) {
164
- const scriptPubkey = binToHex(scriptToLockingBytecode(script, 'p2sh20'));
165
- return `meep debug --tx=${tx} --idx=0 --amt=${utxos[0].satoshis} --pkscript=${scriptPubkey}`;
166
- }
167
167
  export function scriptToAddress(script, network, addressType, tokenSupport) {
168
168
  const lockingBytecode = scriptToLockingBytecode(script, addressType);
169
169
  const prefix = getNetworkPrefix(network);
@@ -249,4 +249,31 @@ function getPushDataOpcode(data) {
249
249
  return Uint8Array.from([0x4c, byteLength]);
250
250
  throw Error('Pushdata too large');
251
251
  }
252
+ const randomInt = () => BigInt(Math.floor(Math.random() * 10000));
253
+ export const randomUtxo = (defaults) => ({
254
+ ...{
255
+ txid: binToHex(sha256(bigIntToVmNumber(randomInt()))),
256
+ vout: Math.floor(Math.random() * 10),
257
+ satoshis: 20000n + randomInt(),
258
+ },
259
+ ...defaults,
260
+ });
261
+ export const randomToken = (defaults) => ({
262
+ ...{
263
+ category: binToHex(sha256(bigIntToVmNumber(randomInt()))),
264
+ amount: 10000n + randomInt(),
265
+ },
266
+ ...defaults,
267
+ });
268
+ export const randomNFT = (defaults) => ({
269
+ ...{
270
+ category: binToHex(sha256(bigIntToVmNumber(randomInt()))),
271
+ amount: 0n,
272
+ nft: {
273
+ commitment: binToHex(sha256(bigIntToVmNumber(randomInt()))).slice(0, 8),
274
+ capability: NonFungibleTokenCapability.none,
275
+ },
276
+ },
277
+ ...defaults,
278
+ });
252
279
  //# sourceMappingURL=utils.js.map
@@ -0,0 +1,9 @@
1
+ export {};
2
+ declare global {
3
+ namespace jest {
4
+ interface Matchers<R> {
5
+ toLog(value: RegExp | string): Promise<void>;
6
+ toFailRequireWith(value: RegExp | string): Promise<void>;
7
+ }
8
+ }
9
+ }
@@ -0,0 +1,66 @@
1
+ import { printExpected, printReceived, matcherHint } from 'jest-matcher-utils';
2
+ expect.extend({
3
+ async toLog(transaction, match) {
4
+ const spyOnLoggerError = jest.spyOn(console, 'log');
5
+ // silence actual stdout output
6
+ spyOnLoggerError.mockImplementation(() => { });
7
+ try {
8
+ await transaction.debug();
9
+ }
10
+ catch { }
11
+ let message = '';
12
+ const failMessage = (received, expected) => () => `${matcherHint('.toLog', 'received', 'expected')}
13
+
14
+ Expected: ${printExpected(expected)}
15
+ Received: ${printReceived(received)}`;
16
+ try {
17
+ expect(spyOnLoggerError).toBeCalledWith(expect.stringMatching(match));
18
+ }
19
+ catch (error) {
20
+ message = error;
21
+ }
22
+ const received = spyOnLoggerError.mock.calls[0][0];
23
+ spyOnLoggerError.mockClear();
24
+ return {
25
+ message: failMessage(received, match),
26
+ pass: !message,
27
+ };
28
+ },
29
+ });
30
+ expect.extend({
31
+ async toFailRequireWith(transaction, match) {
32
+ let message = '';
33
+ let failMessage = () => { };
34
+ try {
35
+ await transaction.debug();
36
+ failMessage = () => () => `${matcherHint('.toFailRequireWith', undefined, '')}
37
+
38
+ Contract function did not fail a require statement`;
39
+ }
40
+ catch (error) {
41
+ message = error;
42
+ }
43
+ // should not have failed
44
+ if (this.isNot) {
45
+ return {
46
+ message: () => `${matcherHint('.toFailRequireWith', 'received', '', { isNot: true })}`,
47
+ pass: false,
48
+ };
49
+ }
50
+ if (message) {
51
+ try {
52
+ expect(message).toMatch(match);
53
+ message = '';
54
+ }
55
+ catch (error) {
56
+ message = error.message;
57
+ failMessage = () => () => message.replace('.toMatch', '.toFailRequireWith');
58
+ }
59
+ }
60
+ return {
61
+ message: failMessage(message, match),
62
+ pass: !message,
63
+ };
64
+ },
65
+ });
66
+ //# sourceMappingURL=JestExtensions.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cashscript",
3
- "version": "0.9.2",
3
+ "version": "0.10.0-next.0",
4
4
  "description": "Easily write and interact with Bitcoin Cash contracts",
5
5
  "keywords": [
6
6
  "bitcoin cash",
@@ -38,26 +38,28 @@
38
38
  "compile:test": "tsc -p tsconfig.test.json",
39
39
  "lint": "eslint . --ext .ts --ignore-path ../../.eslintignore",
40
40
  "prepare": "yarn build",
41
- "prepublishOnly": "yarn test && yarn lint",
41
+ "prepublishOnly": "yarn test",
42
42
  "pretest": "yarn build:test",
43
43
  "test": "NODE_OPTIONS='--experimental-vm-modules --no-warnings' jest"
44
44
  },
45
45
  "dependencies": {
46
46
  "@bitauth/libauth": "^2.0.0-alpha.8",
47
- "@cashscript/utils": "^0.9.2",
47
+ "@cashscript/utils": "^0.10.0-next.0",
48
48
  "bip68": "^1.0.4",
49
49
  "bitcoin-rpc-promise-retry": "^1.3.0",
50
50
  "delay": "^5.0.0",
51
51
  "electrum-cash": "^2.0.10",
52
- "fast-deep-equal": "^3.1.3"
52
+ "fast-deep-equal": "^3.1.3",
53
+ "pako": "^2.1.0"
53
54
  },
54
55
  "devDependencies": {
55
56
  "@jest/globals": "^29.4.1",
56
57
  "@psf/bch-js": "^4.15.0",
58
+ "@types/pako": "^2.0.3",
57
59
  "bip39": "^3.0.4",
58
- "eslint": "^7.20.0",
60
+ "eslint": "^8.54.0",
59
61
  "jest": "^29.4.1",
60
62
  "typescript": "^4.1.5"
61
63
  },
62
- "gitHead": "3cd562a31cc61058f368a8527505ca746cde60d8"
64
+ "gitHead": "3514c438fa3c8069c36f45cc80730293ac85dbdf"
63
65
  }
File without changes
File without changes
File without changes
File without changes
File without changes