cashscript 0.10.0-next.5 → 0.10.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.
package/README.md CHANGED
@@ -1,14 +1,14 @@
1
1
  # CashScript
2
2
 
3
3
  ![Build Status](https://github.com/CashScript/cashscript/actions/workflows/github-actions.yml/badge.svg)
4
- [![Coverage Status](https://img.shields.io/codecov/c/github/Bitcoin-com/cashscript.svg)](https://codecov.io/gh/Bitcoin-com/cashscript/)
4
+ [![Coverage Status](https://img.shields.io/codecov/c/github/CashScript/cashscript.svg)](https://codecov.io/gh/CashScript/cashscript/)
5
5
  [![NPM Version](https://img.shields.io/npm/v/cashscript.svg)](https://www.npmjs.com/package/cashscript)
6
6
  [![NPM Monthly Downloads](https://img.shields.io/npm/dm/cashscript.svg)](https://www.npmjs.com/package/cashscript)
7
7
  [![NPM License](https://img.shields.io/npm/l/cashscript.svg)](https://www.npmjs.com/package/cashscript)
8
8
 
9
9
  CashScript is a high-level programming language for smart contracts on Bitcoin Cash. It offers a strong abstraction layer over Bitcoin Cash' native virtual machine, Bitcoin Script. Its syntax is based on Ethereum's smart contract language Solidity, but its functionality is very different since smart contracts on Bitcoin Cash differ greatly from smart contracts on Ethereum. For a detailed comparison of them, refer to the blog post [*Smart Contracts on Ethereum, Bitcoin and Bitcoin Cash*](https://kalis.me/smart-contracts-eth-btc-bch/).
10
10
 
11
- See the [GitHub repository](https://github.com/Bitcoin-com/cashscript) and the [CashScript website](https://cashscript.org) for full documentation and usage examples.
11
+ See the [GitHub repository](https://github.com/CashScript/cashscript) and the [CashScript website](https://cashscript.org) for full documentation and usage examples.
12
12
 
13
13
  ## The CashScript Language
14
14
  CashScript is a high-level language that allows you to write Bitcoin Cash smart contracts in a straightforward and familiar way. Its syntax is inspired by Ethereum's Solidity language, but its functionality is different since the underlying systems have very different fundamentals. See the [language documentation](https://cashscript.org/docs/language/) for a full reference of the language.
@@ -1,9 +1,10 @@
1
1
  import { AbiFunction, Artifact } from '@cashscript/utils';
2
2
  import SignatureTemplate from './SignatureTemplate.js';
3
- export declare type Argument = bigint | boolean | string | Uint8Array | SignatureTemplate;
4
- export declare type EncodedArgument = Uint8Array | SignatureTemplate;
5
- export declare type EncodeFunction = (arg: Argument, typeStr: string) => EncodedArgument;
6
- export declare function encodeArgument(argument: Argument, typeStr: string): EncodedArgument;
7
- export declare const encodeConstructorArguments: (artifact: Artifact, constructorArgs: Argument[], encodeFunction?: EncodeFunction) => Uint8Array[];
8
- export declare const encodeFunctionArguments: (abiFunction: AbiFunction, functionArgs: Argument[], encodeFunction?: EncodeFunction) => EncodedArgument[];
9
- export declare function encodeArgumentForLibauthTemplate(argument: Argument, typeStr: string): Uint8Array | SignatureTemplate;
3
+ export type ConstructorArgument = bigint | boolean | string | Uint8Array;
4
+ export type FunctionArgument = ConstructorArgument | SignatureTemplate;
5
+ export type EncodedConstructorArgument = Uint8Array;
6
+ export type EncodedFunctionArgument = Uint8Array | SignatureTemplate;
7
+ export type EncodeFunction = (arg: FunctionArgument, typeStr: string) => EncodedFunctionArgument;
8
+ export declare function encodeFunctionArgument(argument: FunctionArgument, typeStr: string): EncodedFunctionArgument;
9
+ export declare const encodeConstructorArguments: (artifact: Artifact, constructorArgs: ConstructorArgument[], encodeFunction?: EncodeFunction) => Uint8Array[];
10
+ export declare const encodeFunctionArguments: (abiFunction: AbiFunction, functionArgs: FunctionArgument[], encodeFunction?: EncodeFunction) => EncodedFunctionArgument[];
package/dist/Argument.js CHANGED
@@ -2,7 +2,7 @@ import { hexToBin } from '@bitauth/libauth';
2
2
  import { BytesType, encodeBool, encodeInt, encodeString, parseType, PrimitiveType, } from '@cashscript/utils';
3
3
  import { TypeError } from './Errors.js';
4
4
  import SignatureTemplate from './SignatureTemplate.js';
5
- export function encodeArgument(argument, typeStr) {
5
+ export function encodeFunctionArgument(argument, typeStr) {
6
6
  let type = parseType(typeStr);
7
7
  if (type === PrimitiveType.BOOL) {
8
8
  if (typeof argument !== 'boolean') {
@@ -50,7 +50,7 @@ export function encodeArgument(argument, typeStr) {
50
50
  }
51
51
  return argument;
52
52
  }
53
- export const encodeConstructorArguments = (artifact, constructorArgs, encodeFunction = encodeArgument) => {
53
+ export const encodeConstructorArguments = (artifact, constructorArgs, encodeFunction = encodeFunctionArgument) => {
54
54
  // Check there's no signature templates in the constructor
55
55
  if (constructorArgs.some((arg) => arg instanceof SignatureTemplate)) {
56
56
  throw new Error('Cannot use signatures in constructor');
@@ -59,15 +59,8 @@ export const encodeConstructorArguments = (artifact, constructorArgs, encodeFunc
59
59
  .map((arg, i) => encodeFunction(arg, artifact.constructorInputs[i].type));
60
60
  return encodedArgs;
61
61
  };
62
- export const encodeFunctionArguments = (abiFunction, functionArgs, encodeFunction = encodeArgument) => {
62
+ export const encodeFunctionArguments = (abiFunction, functionArgs, encodeFunction = encodeFunctionArgument) => {
63
63
  const encodedArgs = functionArgs.map((arg, i) => encodeFunction(arg, abiFunction.inputs[i].type));
64
64
  return encodedArgs;
65
65
  };
66
- // Note: BitAuth IDE requires 0 to be encoded as a single byte (rather than the default empty byte array)
67
- // TODO: Double check this with Pat
68
- export function encodeArgumentForLibauthTemplate(argument, typeStr) {
69
- if (typeStr === PrimitiveType.INT && argument === 0n)
70
- return Uint8Array.from([0]);
71
- return encodeArgument(argument, typeStr);
72
- }
73
66
  //# sourceMappingURL=Argument.js.map
@@ -1,6 +1,6 @@
1
1
  import { Artifact, Script } from '@cashscript/utils';
2
2
  import { Transaction } from './Transaction.js';
3
- import { Argument } from './Argument.js';
3
+ import { ConstructorArgument, FunctionArgument } from './Argument.js';
4
4
  import { Unlocker, ContractOptions, Utxo, AddressType } from './interfaces.js';
5
5
  import NetworkProvider from './network/NetworkProvider.js';
6
6
  export declare class Contract {
@@ -18,11 +18,11 @@ export declare class Contract {
18
18
  provider: NetworkProvider;
19
19
  addressType: AddressType;
20
20
  encodedConstructorArgs: Uint8Array[];
21
- constructor(artifact: Artifact, constructorArgs: Argument[], options?: ContractOptions | undefined);
21
+ constructor(artifact: Artifact, constructorArgs: ConstructorArgument[], options?: ContractOptions | undefined);
22
22
  getBalance(): Promise<bigint>;
23
23
  getUtxos(): Promise<Utxo[]>;
24
24
  private createFunction;
25
25
  private createUnlocker;
26
26
  }
27
- export declare type ContractFunction = (...args: Argument[]) => Transaction;
28
- export declare type ContractUnlocker = (...args: Argument[]) => Unlocker;
27
+ export type ContractFunction = (...args: FunctionArgument[]) => Transaction;
28
+ export type ContractUnlocker = (...args: FunctionArgument[]) => Unlocker;
package/dist/Contract.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { binToHex } from '@bitauth/libauth';
2
2
  import { asmToScript, calculateBytesize, countOpcodes, generateRedeemScript, hash256, scriptToBytecode, } from '@cashscript/utils';
3
3
  import { Transaction } from './Transaction.js';
4
- import { encodeArgument, encodeConstructorArguments, encodeFunctionArguments } from './Argument.js';
4
+ import { encodeFunctionArgument, encodeConstructorArguments, encodeFunctionArguments } from './Argument.js';
5
5
  import { addressToLockScript, createInputScript, createSighashPreimage, scriptToAddress, } from './utils.js';
6
6
  import SignatureTemplate from './SignatureTemplate.js';
7
7
  import { ElectrumNetworkProvider } from './network/index.js';
@@ -16,7 +16,7 @@ export class Contract {
16
16
  throw new Error('Invalid or incomplete artifact provided');
17
17
  }
18
18
  if (artifact.constructorInputs.length !== constructorArgs.length) {
19
- throw new Error(`Incorrect number of arguments passed to ${artifact.contractName} constructor`);
19
+ throw new Error(`Incorrect number of arguments passed to ${artifact.contractName} constructor. Expected ${artifact.constructorInputs.length} arguments (${artifact.constructorInputs.map(input => input.type)}) but got ${constructorArgs.length}`);
20
20
  }
21
21
  // Encode arguments (this also performs type checking)
22
22
  this.encodedConstructorArgs = encodeConstructorArguments(artifact, constructorArgs);
@@ -62,7 +62,7 @@ export class Contract {
62
62
  createFunction(abiFunction, selector) {
63
63
  return (...args) => {
64
64
  if (abiFunction.inputs.length !== args.length) {
65
- throw new Error(`Incorrect number of arguments passed to function ${abiFunction.name}`);
65
+ throw new Error(`Incorrect number of arguments passed to function ${abiFunction.name}. Expected ${abiFunction.inputs.length} arguments (${abiFunction.inputs.map(input => input.type)}) but got ${args.length}`);
66
66
  }
67
67
  // Encode passed args (this also performs type checking)
68
68
  const encodedArgs = encodeFunctionArguments(abiFunction, args);
@@ -72,9 +72,12 @@ export class Contract {
72
72
  }
73
73
  createUnlocker(abiFunction, selector) {
74
74
  return (...args) => {
75
+ if (abiFunction.inputs.length !== args.length) {
76
+ throw new Error(`Incorrect number of arguments passed to function ${abiFunction.name}. Expected ${abiFunction.inputs.length} arguments (${abiFunction.inputs.map(input => input.type)}) but got ${args.length}`);
77
+ }
75
78
  const bytecode = scriptToBytecode(this.redeemScript);
76
79
  const encodedArgs = args
77
- .map((arg, i) => encodeArgument(arg, abiFunction.inputs[i].type));
80
+ .map((arg, i) => encodeFunctionArgument(arg, abiFunction.inputs[i].type));
78
81
  const generateUnlockingBytecode = ({ transaction, sourceOutputs, inputIndex }) => {
79
82
  // TODO: Remove old-style covenant code for v1.0 release
80
83
  let covenantHashType = -1;
package/dist/Errors.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Type } from '@cashscript/utils';
1
+ import { Artifact, RequireStatement, Type } from '@cashscript/utils';
2
2
  export declare class TypeError extends Error {
3
3
  constructor(actual: string, expected: Type);
4
4
  }
@@ -8,62 +8,28 @@ export declare class OutputSatoshisTooSmallError extends Error {
8
8
  export declare class TokensToNonTokenAddressError extends Error {
9
9
  constructor(address: string);
10
10
  }
11
+ export declare class NoDebugInformationInArtifactError extends Error {
12
+ constructor();
13
+ }
11
14
  export declare class FailedTransactionError extends Error {
12
15
  reason: string;
13
- debugStr?: string | undefined;
14
- constructor(reason: string, debugStr?: string | undefined);
15
- }
16
- export declare class FailedRequireError extends FailedTransactionError {
16
+ bitauthUri?: string | undefined;
17
+ constructor(reason: string, bitauthUri?: string | undefined);
17
18
  }
18
- export declare class FailedTimeCheckError extends FailedTransactionError {
19
+ export declare class FailedTransactionEvaluationError extends FailedTransactionError {
20
+ artifact: Artifact;
21
+ failingInstructionPointer: number;
22
+ inputIndex: number;
23
+ bitauthUri: string;
24
+ libauthErrorMessage: string;
25
+ constructor(artifact: Artifact, failingInstructionPointer: number, inputIndex: number, bitauthUri: string, libauthErrorMessage: string);
19
26
  }
20
- export declare class FailedSigCheckError extends FailedTransactionError {
21
- }
22
- export declare enum Reason {
23
- EVAL_FALSE = "Script evaluated without error but finished with a false/empty top stack element",
24
- VERIFY = "Script failed an OP_VERIFY operation",
25
- EQUALVERIFY = "Script failed an OP_EQUALVERIFY operation",
26
- CHECKMULTISIGVERIFY = "Script failed an OP_CHECKMULTISIGVERIFY operation",
27
- CHECKSIGVERIFY = "Script failed an OP_CHECKSIGVERIFY operation",
28
- CHECKDATASIGVERIFY = "Script failed an OP_CHECKDATASIGVERIFY operation",
29
- NUMEQUALVERIFY = "Script failed an OP_NUMEQUALVERIFY operation",
30
- SCRIPT_SIZE = "Script is too big",
31
- PUSH_SIZE = "Push value size limit exceeded",
32
- OP_COUNT = "Operation limit exceeded",
33
- STACK_SIZE = "Stack size limit exceeded",
34
- SIG_COUNT = "Signature count negative or greater than pubkey count",
35
- PUBKEY_COUNT = "Pubkey count negative or limit exceeded",
36
- INVALID_OPERAND_SIZE = "Invalid operand size",
37
- INVALID_NUMBER_RANGE = "Given operand is not a number within the valid range",
38
- IMPOSSIBLE_ENCODING = "The requested encoding is impossible to satisfy",
39
- INVALID_SPLIT_RANGE = "Invalid OP_SPLIT range",
40
- INVALID_BIT_COUNT = "Invalid number of bit set in OP_CHECKMULTISIG",
41
- BAD_OPCODE = "Opcode missing or not understood",
42
- DISABLED_OPCODE = "Attempted to use a disabled opcode",
43
- INVALID_STACK_OPERATION = "Operation not valid with the current stack size",
44
- INVALID_ALTSTACK_OPERATION = "Operation not valid with the current altstack size",
45
- OP_RETURN = "OP_RETURN was encountered",
46
- UNBALANCED_CONDITIONAL = "Invalid OP_IF construction",
47
- DIV_BY_ZERO = "Division by zero error",
48
- MOD_BY_ZERO = "Modulo by zero error",
49
- INVALID_BITFIELD_SIZE = "Bitfield of unexpected size error",
50
- INVALID_BIT_RANGE = "Bitfield's bit out of the expected range",
51
- NEGATIVE_LOCKTIME = "Negative locktime",
52
- UNSATISFIED_LOCKTIME = "Locktime requirement not satisfied",
53
- SIG_HASHTYPE = "Signature hash type missing or not understood",
54
- SIG_DER = "Non-canonical DER signature",
55
- MINIMALDATA = "Data push larger than necessary",
56
- SIG_PUSHONLY = "Only push operators allowed in signature scripts",
57
- SIG_HIGH_S = "Non-canonical signature: S value is unnecessarily high",
58
- MINIMALIF = "OP_IF/NOTIF argument must be minimal",
59
- SIG_NULLFAIL = "Signature must be zero for failed CHECK(MULTI)SIG operation",
60
- SIG_BADLENGTH = "Signature cannot be 65 bytes in CHECKMULTISIG",
61
- SIG_NONSCHNORR = "Only Schnorr signatures allowed in this operation",
62
- DISCOURAGE_UPGRADABLE_NOPS = "NOPx reserved for soft-fork upgrades",
63
- PUBKEYTYPE = "Public key is neither compressed or uncompressed",
64
- CLEANSTACK = "Script did not clean its stack",
65
- NONCOMPRESSED_PUBKEY = "Using non-compressed public key",
66
- ILLEGAL_FORKID = "Illegal use of SIGHASH_FORKID",
67
- MUST_USE_FORKID = "Signature must use SIGHASH_FORKID",
68
- UNKNOWN = "unknown error"
27
+ export declare class FailedRequireError extends FailedTransactionError {
28
+ artifact: Artifact;
29
+ failingInstructionPointer: number;
30
+ requireStatement: RequireStatement;
31
+ inputIndex: number;
32
+ bitauthUri: string;
33
+ libauthErrorMessage?: string | undefined;
34
+ constructor(artifact: Artifact, failingInstructionPointer: number, requireStatement: RequireStatement, inputIndex: number, bitauthUri: string, libauthErrorMessage?: string | undefined);
69
35
  }
package/dist/Errors.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { sourceMapToLocationData } from '@cashscript/utils';
1
2
  export class TypeError extends Error {
2
3
  constructor(actual, expected) {
3
4
  super(`Found type '${actual}' where type '${expected.toString()}' was expected`);
@@ -13,67 +14,68 @@ export class TokensToNonTokenAddressError extends Error {
13
14
  super(`Tried to send tokens to an address without token support, ${address}.`);
14
15
  }
15
16
  }
17
+ export class NoDebugInformationInArtifactError extends Error {
18
+ constructor() {
19
+ super('No debug information found in artifact, please recompile with cashc version 0.10.0 or newer.');
20
+ }
21
+ }
16
22
  export class FailedTransactionError extends Error {
17
- constructor(reason, debugStr) {
18
- super(`Transaction failed with reason: ${reason}${debugStr ? `\n\n${debugStr}` : ''}`);
23
+ constructor(reason, bitauthUri) {
24
+ super(`${reason}${bitauthUri ? `\n\nBitauth URI: ${bitauthUri}` : ''}`);
19
25
  this.reason = reason;
20
- this.debugStr = debugStr;
26
+ this.bitauthUri = bitauthUri;
21
27
  }
22
28
  }
23
- export class FailedRequireError extends FailedTransactionError {
24
- }
25
- export class FailedTimeCheckError extends FailedTransactionError {
29
+ export class FailedTransactionEvaluationError extends FailedTransactionError {
30
+ constructor(artifact, failingInstructionPointer, inputIndex, bitauthUri, libauthErrorMessage) {
31
+ let message = `${artifact.contractName}.cash Error in transaction at input ${inputIndex} in contract ${artifact.contractName}.cash.\nReason: ${libauthErrorMessage}`;
32
+ if (artifact.debug) {
33
+ const { statement, lineNumber } = getLocationDataForInstructionPointer(artifact, failingInstructionPointer);
34
+ message = `${artifact.contractName}.cash:${lineNumber} Error in transaction at input ${inputIndex} in contract ${artifact.contractName}.cash at line ${lineNumber}.\nReason: ${libauthErrorMessage}\nFailing statement: ${statement}`;
35
+ }
36
+ super(message, bitauthUri);
37
+ this.artifact = artifact;
38
+ this.failingInstructionPointer = failingInstructionPointer;
39
+ this.inputIndex = inputIndex;
40
+ this.bitauthUri = bitauthUri;
41
+ this.libauthErrorMessage = libauthErrorMessage;
42
+ }
26
43
  }
27
- export class FailedSigCheckError extends FailedTransactionError {
44
+ export class FailedRequireError extends FailedTransactionError {
45
+ constructor(artifact, failingInstructionPointer, requireStatement, inputIndex, bitauthUri, libauthErrorMessage) {
46
+ let { statement, lineNumber } = getLocationDataForInstructionPointer(artifact, failingInstructionPointer);
47
+ if (!statement.includes('require')) {
48
+ statement = requireStatement.message
49
+ ? `require(${statement}, "${requireStatement.message}")`
50
+ : `require(${statement})`;
51
+ // Sometimes in reconstructed multiline require statements, we get double commas
52
+ statement = statement.replace(/,,/g, ',');
53
+ }
54
+ const baseMessage = `${artifact.contractName}.cash:${lineNumber} Require statement failed at input ${inputIndex} in contract ${artifact.contractName}.cash at line ${lineNumber}`;
55
+ const baseMessageWithRequireMessage = `${baseMessage} with the following message: ${requireStatement.message}`;
56
+ const fullMessage = `${requireStatement.message ? baseMessageWithRequireMessage : baseMessage}.\nFailing statement: ${statement}`;
57
+ super(fullMessage, bitauthUri);
58
+ this.artifact = artifact;
59
+ this.failingInstructionPointer = failingInstructionPointer;
60
+ this.requireStatement = requireStatement;
61
+ this.inputIndex = inputIndex;
62
+ this.bitauthUri = bitauthUri;
63
+ this.libauthErrorMessage = libauthErrorMessage;
64
+ }
28
65
  }
29
- // TODO: Expand these reasons with non-script failures (like tx-mempool-conflict)
30
- export var Reason;
31
- (function (Reason) {
32
- Reason["EVAL_FALSE"] = "Script evaluated without error but finished with a false/empty top stack element";
33
- Reason["VERIFY"] = "Script failed an OP_VERIFY operation";
34
- Reason["EQUALVERIFY"] = "Script failed an OP_EQUALVERIFY operation";
35
- Reason["CHECKMULTISIGVERIFY"] = "Script failed an OP_CHECKMULTISIGVERIFY operation";
36
- Reason["CHECKSIGVERIFY"] = "Script failed an OP_CHECKSIGVERIFY operation";
37
- Reason["CHECKDATASIGVERIFY"] = "Script failed an OP_CHECKDATASIGVERIFY operation";
38
- Reason["NUMEQUALVERIFY"] = "Script failed an OP_NUMEQUALVERIFY operation";
39
- Reason["SCRIPT_SIZE"] = "Script is too big";
40
- Reason["PUSH_SIZE"] = "Push value size limit exceeded";
41
- Reason["OP_COUNT"] = "Operation limit exceeded";
42
- Reason["STACK_SIZE"] = "Stack size limit exceeded";
43
- Reason["SIG_COUNT"] = "Signature count negative or greater than pubkey count";
44
- Reason["PUBKEY_COUNT"] = "Pubkey count negative or limit exceeded";
45
- Reason["INVALID_OPERAND_SIZE"] = "Invalid operand size";
46
- Reason["INVALID_NUMBER_RANGE"] = "Given operand is not a number within the valid range";
47
- Reason["IMPOSSIBLE_ENCODING"] = "The requested encoding is impossible to satisfy";
48
- Reason["INVALID_SPLIT_RANGE"] = "Invalid OP_SPLIT range";
49
- Reason["INVALID_BIT_COUNT"] = "Invalid number of bit set in OP_CHECKMULTISIG";
50
- Reason["BAD_OPCODE"] = "Opcode missing or not understood";
51
- Reason["DISABLED_OPCODE"] = "Attempted to use a disabled opcode";
52
- Reason["INVALID_STACK_OPERATION"] = "Operation not valid with the current stack size";
53
- Reason["INVALID_ALTSTACK_OPERATION"] = "Operation not valid with the current altstack size";
54
- Reason["OP_RETURN"] = "OP_RETURN was encountered";
55
- Reason["UNBALANCED_CONDITIONAL"] = "Invalid OP_IF construction";
56
- Reason["DIV_BY_ZERO"] = "Division by zero error";
57
- Reason["MOD_BY_ZERO"] = "Modulo by zero error";
58
- Reason["INVALID_BITFIELD_SIZE"] = "Bitfield of unexpected size error";
59
- Reason["INVALID_BIT_RANGE"] = "Bitfield's bit out of the expected range";
60
- Reason["NEGATIVE_LOCKTIME"] = "Negative locktime";
61
- Reason["UNSATISFIED_LOCKTIME"] = "Locktime requirement not satisfied";
62
- Reason["SIG_HASHTYPE"] = "Signature hash type missing or not understood";
63
- Reason["SIG_DER"] = "Non-canonical DER signature";
64
- Reason["MINIMALDATA"] = "Data push larger than necessary";
65
- Reason["SIG_PUSHONLY"] = "Only push operators allowed in signature scripts";
66
- Reason["SIG_HIGH_S"] = "Non-canonical signature: S value is unnecessarily high";
67
- Reason["MINIMALIF"] = "OP_IF/NOTIF argument must be minimal";
68
- Reason["SIG_NULLFAIL"] = "Signature must be zero for failed CHECK(MULTI)SIG operation";
69
- Reason["SIG_BADLENGTH"] = "Signature cannot be 65 bytes in CHECKMULTISIG";
70
- Reason["SIG_NONSCHNORR"] = "Only Schnorr signatures allowed in this operation";
71
- Reason["DISCOURAGE_UPGRADABLE_NOPS"] = "NOPx reserved for soft-fork upgrades";
72
- Reason["PUBKEYTYPE"] = "Public key is neither compressed or uncompressed";
73
- Reason["CLEANSTACK"] = "Script did not clean its stack";
74
- Reason["NONCOMPRESSED_PUBKEY"] = "Using non-compressed public key";
75
- Reason["ILLEGAL_FORKID"] = "Illegal use of SIGHASH_FORKID";
76
- Reason["MUST_USE_FORKID"] = "Signature must use SIGHASH_FORKID";
77
- Reason["UNKNOWN"] = "unknown error";
78
- })(Reason || (Reason = {}));
66
+ const getLocationDataForInstructionPointer = (artifact, instructionPointer) => {
67
+ const locationData = sourceMapToLocationData(artifact.debug.sourceMap);
68
+ // We subtract the constructor inputs because these are present in the evaluation (and thus the instruction pointer)
69
+ // but they are not present in the source code (and thus the location data)
70
+ const modifiedInstructionPointer = instructionPointer - artifact.constructorInputs.length;
71
+ const { location } = locationData[modifiedInstructionPointer];
72
+ const failingLines = artifact.source.split('\n').slice(location.start.line - 1, location.end.line);
73
+ // Slice off the start and end of the statement's start and end lines to only return the failing part
74
+ // Note that we first slice off the end, to avoid shifting the end column index
75
+ failingLines[failingLines.length - 1] = failingLines[failingLines.length - 1].slice(0, location.end.column);
76
+ failingLines[0] = failingLines[0].slice(location.start.column);
77
+ const statement = failingLines.join('\n');
78
+ const lineNumber = location.start.line;
79
+ return { statement, lineNumber };
80
+ };
79
81
  //# sourceMappingURL=Errors.js.map
@@ -1,49 +1,55 @@
1
- import { PrimitiveType, bytecodeToScript, formatBitAuthScript, } from '@cashscript/utils';
1
+ import { bytecodeToScript, formatBitAuthScript, } from '@cashscript/utils';
2
2
  import { hexToBin, decodeTransaction, binToHex, binToBase64, utf8ToBin, isHex, } from '@bitauth/libauth';
3
3
  import { deflate } from 'pako';
4
- import { isUtxoP2PKH, } from './interfaces.js';
4
+ import { isUtxoP2PKH, SignatureAlgorithm, HashType, } from './interfaces.js';
5
5
  import SignatureTemplate from './SignatureTemplate.js';
6
6
  import { addressToLockScript, extendedStringify, snakeCase, zip } from './utils.js';
7
- // TODO: Can we change this so we don't need to pass in both the transaction and the transactionHex?
8
7
  export const buildTemplate = async ({ transaction, transactionHex = undefined, // set this argument to prevent unnecessary call `transaction.build()`
9
8
  }) => {
10
9
  const contract = transaction.contract;
11
10
  const txHex = transactionHex ?? await transaction.build();
12
- const hasSignatureTemplates = transaction.inputs.filter((input) => isUtxoP2PKH(input)).length > 0;
13
11
  const template = {
14
12
  $schema: 'https://ide.bitauth.com/authentication-template-v0.schema.json',
15
13
  description: 'Imported from cashscript',
16
14
  name: contract.artifact.contractName,
17
15
  supported: ['BCH_2023_05'],
18
16
  version: 0,
19
- entities: generateTemplateEntities(contract.artifact, transaction.abiFunction),
17
+ entities: generateTemplateEntities(contract.artifact, transaction.abiFunction, transaction.encodedFunctionArgs),
20
18
  scripts: generateTemplateScripts(contract.artifact, contract.addressType, transaction.abiFunction, transaction.encodedFunctionArgs, contract.encodedConstructorArgs),
21
- scenarios: generateTemplateScenarios(contract, transaction, txHex, contract.artifact, transaction.abiFunction, transaction.encodedFunctionArgs, contract.encodedConstructorArgs, hasSignatureTemplates),
19
+ scenarios: generateTemplateScenarios(contract, transaction, txHex, contract.artifact, transaction.abiFunction, transaction.encodedFunctionArgs, contract.encodedConstructorArgs),
22
20
  };
23
- // add extra variables for the p2pkh utxos spent together with our contract
24
- if (hasSignatureTemplates) {
25
- template.entities.parameters.scripts.push('p2pkh_placeholder_lock', 'p2pkh_placeholder_unlock');
21
+ transaction.inputs
22
+ .forEach((input, index) => {
23
+ if (!isUtxoP2PKH(input))
24
+ return;
25
+ const lockScriptName = `p2pkh_placeholder_lock_${index}`;
26
+ const unlockScriptName = `p2pkh_placeholder_unlock_${index}`;
27
+ const placeholderKeyName = `placeholder_key_${index}`;
28
+ const signatureAlgorithmName = getSignatureAlgorithmName(input.template.getSignatureAlgorithm());
29
+ const hashtypeName = getHashTypeName(input.template.getHashType(false));
30
+ const signatureString = `${placeholderKeyName}.${signatureAlgorithmName}.${hashtypeName}`;
31
+ template.entities.parameters.scripts.push(lockScriptName, unlockScriptName);
26
32
  template.entities.parameters.variables = {
27
33
  ...template.entities.parameters.variables,
28
- placeholder_key: {
29
- description: 'placeholder_key',
30
- name: 'placeholder_key',
34
+ [placeholderKeyName]: {
35
+ description: placeholderKeyName,
36
+ name: placeholderKeyName,
31
37
  type: 'Key',
32
38
  },
33
39
  };
34
40
  // add extra unlocking and locking script for P2PKH inputs spent alongside our contract
35
41
  // this is needed for correct cross-referrences in the template
36
- template.scripts.p2pkh_placeholder_unlock = {
37
- name: 'p2pkh_placeholder_unlock',
38
- script: '<placeholder_key.schnorr_signature.all_outputs>\n<placeholder_key.public_key>',
39
- unlocks: 'p2pkh_placeholder_lock',
42
+ template.scripts[unlockScriptName] = {
43
+ name: unlockScriptName,
44
+ script: `<${signatureString}>\n<${placeholderKeyName}.public_key>`,
45
+ unlocks: lockScriptName,
40
46
  };
41
- template.scripts.p2pkh_placeholder_lock = {
47
+ template.scripts[lockScriptName] = {
42
48
  lockingType: 'standard',
43
- name: 'p2pkh_placeholder_lock',
44
- script: 'OP_DUP\nOP_HASH160 <$(<placeholder_key.public_key> OP_HASH160\n)> OP_EQUALVERIFY\nOP_CHECKSIG',
49
+ name: lockScriptName,
50
+ script: `OP_DUP\nOP_HASH160 <$(<${placeholderKeyName}.public_key> OP_HASH160\n)> OP_EQUALVERIFY\nOP_CHECKSIG`,
45
51
  };
46
- }
52
+ });
47
53
  return template;
48
54
  };
49
55
  export const getBitauthUri = (template) => {
@@ -51,13 +57,13 @@ export const getBitauthUri = (template) => {
51
57
  const payload = base64toBase64Url(binToBase64(deflate(utf8ToBin(extendedStringify(template)))));
52
58
  return `https://ide.bitauth.com/import-template/${payload}`;
53
59
  };
54
- const generateTemplateEntities = (artifact, abiFunction) => {
55
- const functionParameters = Object.fromEntries(abiFunction.inputs.map((input) => ([
60
+ const generateTemplateEntities = (artifact, abiFunction, encodedFunctionArgs) => {
61
+ const functionParameters = Object.fromEntries(abiFunction.inputs.map((input, index) => ([
56
62
  snakeCase(input.name),
57
63
  {
58
64
  description: `"${input.name}" parameter of function "${abiFunction.name}"`,
59
65
  name: input.name,
60
- type: input.type === PrimitiveType.SIG ? 'Key' : 'WalletData',
66
+ type: encodedFunctionArgs[index] instanceof SignatureTemplate ? 'Key' : 'WalletData',
61
67
  },
62
68
  ])));
63
69
  const constructorParameters = Object.fromEntries(artifact.constructorInputs.map((input) => ([
@@ -130,7 +136,7 @@ const generateTemplateUnlockScript = (artifact, abiFunction, encodedFunctionArgs
130
136
  unlocks: 'lock',
131
137
  };
132
138
  };
133
- const generateTemplateScenarios = (contract, transaction, transactionHex, artifact, abiFunction, encodedFunctionArgs, encodedConstructorArgs, hasSignatureTemplates) => {
139
+ const generateTemplateScenarios = (contract, transaction, transactionHex, artifact, abiFunction, encodedFunctionArgs, encodedConstructorArgs) => {
134
140
  const libauthTransaction = decodeTransaction(hexToBin(transactionHex));
135
141
  if (typeof libauthTransaction === 'string')
136
142
  throw Error(libauthTransaction);
@@ -145,11 +151,10 @@ const generateTemplateScenarios = (contract, transaction, transactionHex, artifa
145
151
  ...generateTemplateScenarioParametersValues(abiFunction.inputs, encodedFunctionArgs),
146
152
  ...generateTemplateScenarioParametersValues(artifact.constructorInputs, encodedConstructorArgs),
147
153
  },
148
- // TODO: Don't hardcode these values
149
154
  currentBlockHeight: 2,
150
155
  currentBlockTime: Math.round(+new Date() / 1000),
151
156
  keys: {
152
- privateKeys: generateTemplateScenarioKeys(abiFunction.inputs, encodedFunctionArgs, hasSignatureTemplates),
157
+ privateKeys: generateTemplateScenarioKeys(abiFunction.inputs, encodedFunctionArgs),
153
158
  },
154
159
  },
155
160
  transaction: generateTemplateScenarioTransaction(contract, libauthTransaction, transaction),
@@ -165,21 +170,17 @@ const generateTemplateScenarios = (contract, transaction, transactionHex, artifa
165
170
  const generateTemplateScenarioTransaction = (contract, libauthTransaction, csTransaction) => {
166
171
  const slotIndex = csTransaction.inputs.findIndex((input) => !isUtxoP2PKH(input));
167
172
  const inputs = libauthTransaction.inputs.map((input, index) => {
168
- const csInput = csTransaction.inputs[index]; // TODO: Change
173
+ const csInput = csTransaction.inputs[index];
169
174
  return {
170
175
  outpointIndex: input.outpointIndex,
171
- outpointTransactionHash:
172
- // TODO: This should always be Uint8Array according to the libauth transaction types
173
- input.outpointTransactionHash instanceof Uint8Array
174
- ? binToHex(input.outpointTransactionHash)
175
- : input.outpointTransactionHash,
176
+ outpointTransactionHash: binToHex(input.outpointTransactionHash),
176
177
  sequenceNumber: input.sequenceNumber,
177
- unlockingBytecode: generateTemplateScenarioBytecode(csInput, 'p2pkh_placeholder_unlock', index === slotIndex),
178
+ unlockingBytecode: generateTemplateScenarioBytecode(csInput, `p2pkh_placeholder_unlock_${index}`, index === slotIndex),
178
179
  };
179
180
  });
180
181
  const locktime = libauthTransaction.locktime;
181
182
  const outputs = libauthTransaction.outputs.map((output, index) => {
182
- const csOutput = csTransaction.outputs[index]; // TODO: Change
183
+ const csOutput = csTransaction.outputs[index];
183
184
  return {
184
185
  lockingBytecode: generateTemplateScenarioTransactionOutputLockingBytecode(csOutput, contract),
185
186
  token: serialiseTokenDetails(output.token),
@@ -200,7 +201,7 @@ const generateTemplateScenarioSourceOutputs = (csTransaction) => {
200
201
  const slotIndex = csTransaction.inputs.findIndex((input) => !isUtxoP2PKH(input));
201
202
  return csTransaction.inputs.map((input, index) => {
202
203
  return {
203
- lockingBytecode: generateTemplateScenarioBytecode(input, 'p2pkh_placeholder_lock', index === slotIndex),
204
+ lockingBytecode: generateTemplateScenarioBytecode(input, `p2pkh_placeholder_lock_${index}`, index === slotIndex),
204
205
  valueSatoshis: Number(input.satoshis),
205
206
  token: serialiseTokenDetails(input.token),
206
207
  };
@@ -229,21 +230,17 @@ const generateTemplateScenarioParametersValues = (types, encodedArgs) => {
229
230
  .filter(([, arg]) => !(arg instanceof SignatureTemplate))
230
231
  .map(([input, arg]) => {
231
232
  const encodedArgumentHex = binToHex(arg);
232
- // TODO: Is this really necessary?
233
- const prefixedEncodedArgument = encodedArgumentHex.length ? `0x${encodedArgumentHex}` : encodedArgumentHex;
233
+ const prefixedEncodedArgument = encodedArgumentHex.length > 0 ? `0x${encodedArgumentHex}` : '';
234
234
  return [snakeCase(input.name), prefixedEncodedArgument];
235
235
  });
236
236
  return Object.fromEntries(entries);
237
237
  };
238
- const generateTemplateScenarioKeys = (types, encodedArgs, hasSignatureTemplates) => {
238
+ const generateTemplateScenarioKeys = (types, encodedArgs) => {
239
239
  const typesAndArguments = zip(types, encodedArgs);
240
240
  const entries = typesAndArguments
241
241
  .filter(([, arg]) => arg instanceof SignatureTemplate)
242
242
  .map(([input, arg]) => [snakeCase(input.name), binToHex(arg.privateKey)]);
243
- const placeholderKey = hasSignatureTemplates
244
- ? [['placeholder_key', '0x0000000000000000000000000000000000000000000000000000000000000000']]
245
- : [];
246
- return Object.fromEntries([...entries, ...placeholderKey]);
243
+ return Object.fromEntries(entries);
247
244
  };
248
245
  const formatParametersForDebugging = (types, args) => {
249
246
  if (types.length === 0)
@@ -252,8 +249,9 @@ const formatParametersForDebugging = (types, args) => {
252
249
  const typesAndArguments = zip(types, args).reverse();
253
250
  return typesAndArguments.map(([input, arg]) => {
254
251
  if (arg instanceof SignatureTemplate) {
255
- // TODO: Different signing algorithms / hashtypes
256
- return `<${snakeCase(input.name)}.schnorr_signature.all_outputs> // ${input.type}`;
252
+ const signatureAlgorithmName = getSignatureAlgorithmName(arg.getSignatureAlgorithm());
253
+ const hashtypeName = getHashTypeName(arg.getHashType(false));
254
+ return `<${snakeCase(input.name)}.${signatureAlgorithmName}.${hashtypeName}> // ${input.type}`;
257
255
  }
258
256
  const typeStr = input.type === 'bytes' ? `bytes${arg.length}` : input.type;
259
257
  // we output these values as pushdata, comment will contain the type and the value of the variable
@@ -261,9 +259,32 @@ const formatParametersForDebugging = (types, args) => {
261
259
  return `<${snakeCase(input.name)}> // ${typeStr} = <${`0x${binToHex(arg)}`}>`;
262
260
  }).join('\n');
263
261
  };
262
+ const getSignatureAlgorithmName = (signatureAlgorithm) => {
263
+ const signatureAlgorithmNames = {
264
+ [SignatureAlgorithm.SCHNORR]: 'schnorr_signature',
265
+ [SignatureAlgorithm.ECDSA]: 'ecdsa_signature',
266
+ };
267
+ return signatureAlgorithmNames[signatureAlgorithm];
268
+ };
269
+ const getHashTypeName = (hashType) => {
270
+ const hashtypeNames = {
271
+ [HashType.SIGHASH_ALL]: 'all_outputs',
272
+ [HashType.SIGHASH_ALL | HashType.SIGHASH_ANYONECANPAY]: 'all_outputs_single_input',
273
+ [HashType.SIGHASH_ALL | HashType.SIGHASH_UTXOS]: 'all_outputs_all_utxos',
274
+ [HashType.SIGHASH_ALL | HashType.SIGHASH_ANYONECANPAY | HashType.SIGHASH_UTXOS]: 'all_outputs_single_input_INVALID_all_utxos',
275
+ [HashType.SIGHASH_SINGLE]: 'corresponding_output',
276
+ [HashType.SIGHASH_SINGLE | HashType.SIGHASH_ANYONECANPAY]: 'corresponding_output_single_input',
277
+ [HashType.SIGHASH_SINGLE | HashType.SIGHASH_UTXOS]: 'corresponding_output_all_utxos',
278
+ [HashType.SIGHASH_SINGLE | HashType.SIGHASH_ANYONECANPAY | HashType.SIGHASH_UTXOS]: 'corresponding_output_single_input_INVALID_all_utxos',
279
+ [HashType.SIGHASH_NONE]: 'no_outputs',
280
+ [HashType.SIGHASH_NONE | HashType.SIGHASH_ANYONECANPAY]: 'no_outputs_single_input',
281
+ [HashType.SIGHASH_NONE | HashType.SIGHASH_UTXOS]: 'no_outputs_all_utxos',
282
+ [HashType.SIGHASH_NONE | HashType.SIGHASH_ANYONECANPAY | HashType.SIGHASH_UTXOS]: 'no_outputs_single_input_INVALID_all_utxos',
283
+ };
284
+ return hashtypeNames[hashType];
285
+ };
264
286
  const formatBytecodeForDebugging = (artifact) => {
265
287
  if (!artifact.debug) {
266
- // TODO: See if we can merge this with code from @cashscript/utils -> script.ts
267
288
  return artifact.bytecode
268
289
  .split(' ')
269
290
  .map((asmElement) => (isHex(asmElement) ? `<0x${asmElement}>` : asmElement))
@@ -271,7 +292,6 @@ const formatBytecodeForDebugging = (artifact) => {
271
292
  }
272
293
  return formatBitAuthScript(bytecodeToScript(hexToBin(artifact.debug.bytecode)), artifact.debug.sourceMap, artifact.source);
273
294
  };
274
- // TODO: Maybe move / refactor
275
295
  const serialiseTokenDetails = (token) => {
276
296
  if (!token)
277
297
  return undefined;
@@ -6,6 +6,7 @@ export default class SignatureTemplate {
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;
9
+ getSignatureAlgorithm(): SignatureAlgorithm;
9
10
  getPublicKey(): Uint8Array;
10
11
  unlockP2PKH(): Unlocker;
11
12
  }
@@ -27,6 +27,9 @@ export default class SignatureTemplate {
27
27
  getHashType(bchForkId = true) {
28
28
  return bchForkId ? (this.hashtype | SigningSerializationFlag.forkId) : this.hashtype;
29
29
  }
30
+ getSignatureAlgorithm() {
31
+ return this.signatureAlgorithm;
32
+ }
30
33
  getPublicKey() {
31
34
  return secp256k1.derivePublicKeyCompressed(this.privateKey);
32
35
  }
@@ -4,12 +4,12 @@ import { Utxo, Output, Recipient, TokenDetails, TransactionDetails, Unlocker } f
4
4
  import SignatureTemplate from './SignatureTemplate.js';
5
5
  import { Contract } from './Contract.js';
6
6
  import { DebugResult } from './debugging.js';
7
- import { EncodedArgument } from './Argument.js';
7
+ import { EncodedFunctionArgument } from './Argument.js';
8
8
  export declare class Transaction {
9
9
  contract: Contract;
10
10
  private unlocker;
11
11
  abiFunction: AbiFunction;
12
- encodedFunctionArgs: EncodedArgument[];
12
+ encodedFunctionArgs: EncodedFunctionArgument[];
13
13
  private selector?;
14
14
  inputs: Utxo[];
15
15
  outputs: Output[];
@@ -19,7 +19,7 @@ export declare class Transaction {
19
19
  private hardcodedFee;
20
20
  private minChange;
21
21
  private tokenChange;
22
- constructor(contract: Contract, unlocker: Unlocker, abiFunction: AbiFunction, encodedFunctionArgs: EncodedArgument[], selector?: number | undefined);
22
+ constructor(contract: Contract, unlocker: Unlocker, abiFunction: AbiFunction, encodedFunctionArgs: EncodedFunctionArgument[], selector?: number | undefined);
23
23
  from(input: Utxo): this;
24
24
  from(inputs: Utxo[]): this;
25
25
  fromP2PKH(input: Utxo, template: SignatureTemplate): this;
@@ -4,13 +4,13 @@ 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 { createInputScript, getInputSize, createOpReturnOutput, getTxSizeWithoutInputs, getPreimageSize, buildError, validateOutput, utxoComparator, calculateDust, getOutputSize, utxoTokenComparator, } from './utils.js';
7
+ import { createInputScript, getInputSize, createOpReturnOutput, getTxSizeWithoutInputs, getPreimageSize, 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
11
  import { buildTemplate, getBitauthUri } from './LibauthTemplate.js';
13
- import { debugTemplate, evaluateTemplate } from './debugging.js';
12
+ import { debugTemplate } from './debugging.js';
13
+ import { FailedTransactionError } from './Errors.js';
14
14
  export class Transaction {
15
15
  constructor(contract, unlocker, abiFunction, encodedFunctionArgs, selector) {
16
16
  this.contract = contract;
@@ -101,45 +101,25 @@ export class Transaction {
101
101
  }
102
102
  async send(raw) {
103
103
  const tx = await this.build();
104
- let template;
104
+ // Debug the transaction locally before sending so any errors are caught early
105
+ // Libauth debugging does not work with old-style covenants
106
+ if (!this.abiFunction.covenant) {
107
+ await this.debug();
108
+ }
105
109
  try {
106
- if (this.contract.provider instanceof MockNetworkProvider) {
107
- template = await buildTemplate({
108
- transaction: this,
109
- transactionHex: tx,
110
- });
111
- evaluateTemplate(template);
112
- }
113
110
  const txid = await this.contract.provider.sendRawTransaction(tx);
114
111
  return raw ? await this.getTxDetails(txid, raw) : await this.getTxDetails(txid);
115
112
  }
116
- catch (maybeNodeError) {
117
- if (!template) {
118
- template = await buildTemplate({
119
- transaction: this,
120
- transactionHex: tx,
121
- });
122
- }
123
- const reason = maybeNodeError.error ?? maybeNodeError.message ?? maybeNodeError;
124
- const bitauthUri = getBitauthUri(template);
125
- try {
126
- debugTemplate(template, this.contract.artifact);
127
- }
128
- catch (libauthError) {
129
- if (this.contract.provider instanceof MockNetworkProvider) {
130
- throw buildError(libauthError, bitauthUri);
131
- }
132
- else {
133
- const message = `${libauthError}\n\nUnderlying node error: ${reason}`;
134
- throw buildError(message, bitauthUri);
135
- }
136
- }
137
- // this must be unreachable
138
- throw buildError(reason, bitauthUri);
113
+ catch (error) {
114
+ const reason = error.error ?? error.message ?? error;
115
+ throw new FailedTransactionError(reason, await this.bitauthUri());
139
116
  }
140
117
  }
141
118
  // method to debug the transaction with libauth VM, throws upon evaluation error
142
119
  async debug() {
120
+ if (!this.contract.artifact.debug) {
121
+ console.warn('No debug information found in artifact. Recompile with cashc version 0.10.0 or newer to get better debugging information.');
122
+ }
143
123
  const template = await this.getLibauthTemplate();
144
124
  return debugTemplate(template, this.contract.artifact);
145
125
  }
@@ -169,7 +149,7 @@ export class Transaction {
169
149
  }
170
150
  async setInputsAndOutputs() {
171
151
  if (this.outputs.length === 0) {
172
- throw Error('Attempted to build a transaction without outputs');
152
+ throw new Error('Attempted to build a transaction without outputs');
173
153
  }
174
154
  // Fetched utxos are only used when no inputs are available, so only fetch in that case.
175
155
  const allUtxos = this.inputs.length === 0
@@ -4,9 +4,9 @@ export interface TransactionBuilderOptions {
4
4
  provider: NetworkProvider;
5
5
  }
6
6
  export declare class TransactionBuilder {
7
- private provider;
8
- private inputs;
9
- private outputs;
7
+ provider: NetworkProvider;
8
+ inputs: UnlockableUtxo[];
9
+ outputs: Output[];
10
10
  private locktime;
11
11
  private maxFee?;
12
12
  constructor(options: TransactionBuilderOptions);
@@ -1,7 +1,8 @@
1
1
  import { binToHex, decodeTransaction, encodeTransaction, hexToBin, } from '@bitauth/libauth';
2
2
  import delay from 'delay';
3
3
  import { isUnlockableUtxo, } from './interfaces.js';
4
- import { buildError, cashScriptOutputToLibauthOutput, createOpReturnOutput, validateOutput, } from './utils.js';
4
+ import { cashScriptOutputToLibauthOutput, createOpReturnOutput, validateOutput, } from './utils.js';
5
+ import { FailedTransactionError } from './Errors.js';
5
6
  const DEFAULT_SEQUENCE = 0xfffffffe;
6
7
  export class TransactionBuilder {
7
8
  constructor(options) {
@@ -94,7 +95,7 @@ export class TransactionBuilder {
94
95
  }
95
96
  catch (e) {
96
97
  const reason = e.error ?? e.message;
97
- throw buildError(reason);
98
+ throw new FailedTransactionError(reason);
98
99
  }
99
100
  }
100
101
  async getTxDetails(txid, raw) {
@@ -1,5 +1,5 @@
1
1
  import { AuthenticationProgramStateCommon, WalletTemplate } from '@bitauth/libauth';
2
2
  import { Artifact } from '@cashscript/utils';
3
3
  export declare const evaluateTemplate: (template: WalletTemplate) => boolean;
4
- export declare type DebugResult = AuthenticationProgramStateCommon[];
4
+ export type DebugResult = AuthenticationProgramStateCommon[];
5
5
  export declare const debugTemplate: (template: WalletTemplate, artifact: Artifact) => DebugResult;
package/dist/debugging.js CHANGED
@@ -1,12 +1,14 @@
1
- import { AuthenticationErrorCommon, binToHex, createCompiler, createVirtualMachineBCH2023, walletTemplateToCompilerConfiguration } from '@bitauth/libauth';
2
- import { Op, PrimitiveType, decodeBool, decodeInt, decodeString } from '@cashscript/utils';
1
+ import { AuthenticationErrorCommon, binToHex, createCompiler, createVirtualMachineBCH2023, encodeAuthenticationInstruction, walletTemplateToCompilerConfiguration } from '@bitauth/libauth';
2
+ import { Op, PrimitiveType, bytecodeToAsm, decodeBool, decodeInt, decodeString } from '@cashscript/utils';
3
3
  import { findLastIndex, toRegExp } from './utils.js';
4
+ import { FailedRequireError, FailedTransactionError, FailedTransactionEvaluationError } from './Errors.js';
5
+ import { getBitauthUri } from './LibauthTemplate.js';
4
6
  // evaluates the fully defined template, throws upon error
5
7
  export const evaluateTemplate = (template) => {
6
8
  const { vm, program } = createProgram(template);
7
9
  const verifyResult = vm.verify(program);
8
10
  if (typeof verifyResult === 'string') {
9
- throw new Error(verifyResult);
11
+ throw new FailedTransactionError(verifyResult, getBitauthUri(template));
10
12
  }
11
13
  return verifyResult;
12
14
  };
@@ -24,34 +26,48 @@ export const debugTemplate = (template, artifact) => {
24
26
  const executedLogs = (artifact.debug?.logs ?? [])
25
27
  .filter((debugStep) => executedDebugSteps.some((log) => log.ip === debugStep.ip));
26
28
  for (const log of executedLogs) {
27
- const correspondingDebugStep = executedDebugSteps.find((debugStep) => debugStep.ip === log.ip);
28
- logConsoleLogStatement(log, correspondingDebugStep, artifact);
29
+ logConsoleLogStatement(log, executedDebugSteps, artifact);
29
30
  }
30
31
  const lastExecutedDebugStep = executedDebugSteps[executedDebugSteps.length - 1];
31
32
  // If an error is present in the last step, that means a require statement in the middle of the function failed
32
33
  if (lastExecutedDebugStep.error) {
34
+ // In Libauth any thrown error gets registered in the instruction that happens right *after* the instruction that
35
+ // caused the error (in other words the OP_VERIFY). We need to decrement the instruction pointer to get the correct
36
+ // failing instruction.
37
+ const failingIp = lastExecutedDebugStep.ip - 1;
38
+ // Generally speaking, an error is thrown by the OP_VERIFY opcode, but for NULLFAIL, the error is thrown in the
39
+ // preceding OP_CHECKSIG opcode. The error message is registered in the next instruction, so we need to increment
40
+ // the instruction pointer to get the correct error message from the require messages in the artifact.
41
+ // Note that we do NOT use this adjusted IP when passing the failing IP into the FailedRequireError
33
42
  const isNullFail = lastExecutedDebugStep.error === AuthenticationErrorCommon.nonNullSignatureFailure;
34
- const messageIp = lastExecutedDebugStep.ip + (isNullFail ? 1 : 0);
35
- const requireStatement = (artifact.debug?.requireMessages ?? [])
36
- .find((message) => message.ip === messageIp);
43
+ const requireStatementIp = failingIp + (isNullFail ? 1 : 0);
44
+ const requireStatement = (artifact.debug?.requires ?? [])
45
+ .find((statement) => statement.ip === requireStatementIp);
46
+ const { program: { inputIndex }, error } = lastExecutedDebugStep;
37
47
  if (requireStatement) {
38
- throw new Error(`${artifact.contractName}.cash:${requireStatement.line} Error in evaluating input index ${lastExecutedDebugStep.program.inputIndex} with the following message: ${requireStatement.message}.\n${lastExecutedDebugStep.error}`);
48
+ // Note that we use failingIp here rather than requireStatementIp, see comment above
49
+ throw new FailedRequireError(artifact, failingIp, requireStatement, inputIndex, getBitauthUri(template), error);
39
50
  }
40
- throw new Error(`Error in evaluating input index ${lastExecutedDebugStep.program.inputIndex}.\n${lastExecutedDebugStep.error}`);
51
+ // Note that we use failingIp here rather than requireStatementIp, see comment above
52
+ throw new FailedTransactionEvaluationError(artifact, failingIp, inputIndex, getBitauthUri(template), error);
41
53
  }
42
54
  const evaluationResult = vm.verify(program);
43
55
  if (failedFinalVerify(evaluationResult)) {
44
- const stackContents = lastExecutedDebugStep.stack.map(item => `0x${binToHex(item)}`).join(', ');
45
- const stackContentsMessage = `\nStack contents after evaluation: ${lastExecutedDebugStep.stack.length ? stackContents : 'empty'}`;
46
- const executedInstructions = lastExecutedDebugStep.instructions
47
- .filter((_, i) => executedDebugSteps.map((step) => step.ip).includes(i));
48
- const cleanupSize = calculateCleanupSize(executedInstructions);
49
- const finalExecutedVerify = executedDebugSteps[executedDebugSteps.length - cleanupSize - 1];
50
- const finalVerifyMessage = artifact.debug?.requireMessages.find((message) => message.ip === finalExecutedVerify.ip);
51
- if (finalVerifyMessage) {
52
- throw new Error(`${artifact.contractName}.cash:${finalVerifyMessage.line} Error in evaluating input index ${lastExecutedDebugStep.program.inputIndex} with the following message: ${finalVerifyMessage.message}.\n${evaluationResult.replace(/Error in evaluating input index \d: /, '')}` + stackContentsMessage);
56
+ const finalExecutedVerifyIp = getFinalExecutedVerifyIp(executedDebugSteps);
57
+ // The final executed verify instruction points to the "implicit" VERIFY that is added at the end of the script.
58
+ // This instruction does not exist in the sourcemap, so we need to decrement the instruction pointer to get the
59
+ // actual final executed statement (which is *not* the require statement, but the evaluation within)
60
+ const sourcemapInstructionPointer = finalExecutedVerifyIp - 1;
61
+ // logDebugSteps(executedDebugSteps, lastExecutedDebugStep.instructions);
62
+ // console.warn('message', finalExecutedVerifyIp);
63
+ // console.warn(artifact.debug?.requires);
64
+ const requireStatement = (artifact.debug?.requires ?? [])
65
+ .find((message) => message.ip === finalExecutedVerifyIp);
66
+ const { program: { inputIndex } } = lastExecutedDebugStep;
67
+ if (requireStatement) {
68
+ throw new FailedRequireError(artifact, sourcemapInstructionPointer, requireStatement, inputIndex, getBitauthUri(template));
53
69
  }
54
- throw new Error(evaluationResult + stackContentsMessage);
70
+ throw new FailedTransactionEvaluationError(artifact, sourcemapInstructionPointer, inputIndex, getBitauthUri(template), evaluationResult);
55
71
  }
56
72
  return fullDebugSteps;
57
73
  };
@@ -67,25 +83,28 @@ const createProgram = (template) => {
67
83
  scenarioId: 'evaluate_function',
68
84
  });
69
85
  if (typeof scenarioGeneration === 'string') {
70
- throw new Error(scenarioGeneration);
86
+ throw new FailedTransactionError(scenarioGeneration, getBitauthUri(template));
71
87
  }
72
88
  if (typeof scenarioGeneration.scenario === 'string') {
73
- throw new Error(scenarioGeneration.scenario);
89
+ throw new FailedTransactionError(scenarioGeneration.scenario, getBitauthUri(template));
74
90
  }
75
91
  return { vm, program: scenarioGeneration.scenario.program };
76
92
  };
77
- const logConsoleLogStatement = (log, debugStep, artifact) => {
93
+ const logConsoleLogStatement = (log, debugSteps, artifact) => {
78
94
  let line = `${artifact.contractName}.cash:${log.line}`;
79
- const decodedData = log.data.map((element) => decodeLogData(element, debugStep.stack, log.ip));
95
+ const decodedData = log.data.map((element) => {
96
+ if (typeof element === 'string')
97
+ return element;
98
+ const debugStep = debugSteps.find((step) => step.ip === element.ip);
99
+ return decodeStackItem(element, debugStep.stack);
100
+ });
80
101
  console.log(`${line} ${decodedData.join(' ')}`);
81
102
  };
82
- const decodeLogData = (element, stack, ip) => {
83
- if (typeof element === 'string')
84
- return element;
103
+ const decodeStackItem = (element, stack) => {
85
104
  // Reversed since stack is in reverse order
86
105
  const stackItem = [...stack].reverse()[element.stackIndex];
87
106
  if (!stackItem) {
88
- throw Error(`Stack item at index ${element.stackIndex} not found at instruction pointer ${ip}`);
107
+ throw Error(`Stack item at index ${element.stackIndex} not found at instruction pointer ${element.ip}`);
89
108
  }
90
109
  if (element.type === PrimitiveType.BOOL)
91
110
  return decodeBool(stackItem);
@@ -113,7 +132,9 @@ const calculateCleanupSize = (instructions) => {
113
132
  const cleanupOpcodes = [Op.OP_ENDIF, Op.OP_NIP, Op.OP_ELSE];
114
133
  let cleanupSize = 0;
115
134
  for (const instruction of [...instructions].reverse()) {
116
- if (cleanupOpcodes.includes(instruction.opcode)) {
135
+ // The instructions array may contain undefined elements for the final executed debug steps that are not
136
+ // technically instructions (e.g. the final *implicit* verify). We still want to get rid of these in the cleanup
137
+ if (!instruction || cleanupOpcodes.includes(instruction.opcode)) {
117
138
  cleanupSize++;
118
139
  }
119
140
  else {
@@ -122,4 +143,23 @@ const calculateCleanupSize = (instructions) => {
122
143
  }
123
144
  return cleanupSize;
124
145
  };
146
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
147
+ const logDebugSteps = (debugSteps, instructions) => {
148
+ debugSteps.map((step) => {
149
+ const opcode = instructions[step.ip] ? bytecodeToAsm(encodeAuthenticationInstruction(instructions[step.ip])) : 'null';
150
+ console.warn(step.ip, opcode, step.stack, step.error);
151
+ });
152
+ };
153
+ const getFinalExecutedVerifyIp = (executedDebugSteps) => {
154
+ // Map every executed debug step to its corresponding instruction
155
+ // (note that the last executed step(s) may not have a corresponding instruction and will be `undefined`)
156
+ const executedInstructions = executedDebugSteps.map((step) => step.instructions[step.ip]);
157
+ const finalExecutedDebugStepIndex = executedDebugSteps.length - 1;
158
+ const cleanupSize = calculateCleanupSize(executedInstructions);
159
+ const finalExecutedNonCleanupStep = executedDebugSteps[finalExecutedDebugStepIndex - cleanupSize];
160
+ // The final verify in a function is dropped, so after cleanup, we get the final OP that was executed *before* the
161
+ // final verify, so we need to add one to get the actual final verify instruction
162
+ const finalExecutedVerifyIp = finalExecutedNonCleanupStep.ip + 1;
163
+ return finalExecutedVerifyIp;
164
+ };
125
165
  //# sourceMappingURL=debugging.js.map
package/dist/index.d.ts CHANGED
@@ -1,12 +1,11 @@
1
- import SignatureTemplate from './SignatureTemplate.js';
2
- export { SignatureTemplate };
3
- export { Contract, ContractFunction } from './Contract.js';
1
+ export { default as SignatureTemplate } from './SignatureTemplate.js';
2
+ export { Contract, type ContractFunction } from './Contract.js';
4
3
  export { Transaction } from './Transaction.js';
5
4
  export { TransactionBuilder } from './TransactionBuilder.js';
6
- export { Argument, encodeArgument } from './Argument.js';
7
- export { Artifact, AbiFunction, AbiInput } from '@cashscript/utils';
5
+ export { type ConstructorArgument, type FunctionArgument, type EncodedConstructorArgument, type EncodedFunctionArgument, encodeFunctionArgument, } from './Argument.js';
6
+ export type { Artifact, AbiFunction, AbiInput } from '@cashscript/utils';
8
7
  export * as utils from '@cashscript/utils';
9
8
  export * from './interfaces.js';
10
9
  export * from './Errors.js';
11
- export { NetworkProvider, BitcoinRpcNetworkProvider, ElectrumNetworkProvider, FullStackNetworkProvider, MockNetworkProvider, } from './network/index.js';
10
+ export { type NetworkProvider, BitcoinRpcNetworkProvider, ElectrumNetworkProvider, FullStackNetworkProvider, MockNetworkProvider, } from './network/index.js';
12
11
  export { randomUtxo, randomToken, randomNFT } from './utils.js';
package/dist/index.js CHANGED
@@ -1,9 +1,8 @@
1
- import SignatureTemplate from './SignatureTemplate.js';
2
- export { SignatureTemplate };
1
+ export { default as SignatureTemplate } from './SignatureTemplate.js';
3
2
  export { Contract } from './Contract.js';
4
3
  export { Transaction } from './Transaction.js';
5
4
  export { TransactionBuilder } from './TransactionBuilder.js';
6
- export { encodeArgument } from './Argument.js';
5
+ export { encodeFunctionArgument, } from './Argument.js';
7
6
  export * as utils from '@cashscript/utils';
8
7
  export * from './interfaces.js';
9
8
  export * from './Errors.js';
@@ -82,7 +82,7 @@ export declare const Network: {
82
82
  CHIPNET: "chipnet";
83
83
  REGTEST: "regtest";
84
84
  };
85
- export declare type Network = (typeof Network)[keyof typeof Network];
85
+ export type Network = (typeof Network)[keyof typeof Network];
86
86
  export interface TransactionDetails extends Transaction {
87
87
  txid: string;
88
88
  hex: string;
@@ -91,4 +91,4 @@ export interface ContractOptions {
91
91
  provider?: NetworkProvider;
92
92
  addressType?: AddressType;
93
93
  }
94
- export declare type AddressType = 'p2sh20' | 'p2sh32';
94
+ export type AddressType = 'p2sh20' | 'p2sh32';
@@ -1,4 +1,4 @@
1
- export { default as NetworkProvider } from './NetworkProvider.js';
1
+ export type { 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';
@@ -4,6 +4,7 @@ declare global {
4
4
  interface Matchers<R> {
5
5
  toLog(value?: RegExp | string): Promise<void>;
6
6
  toFailRequireWith(value: RegExp | string): Promise<void>;
7
+ toFailRequire(): Promise<void>;
7
8
  }
8
9
  }
9
10
  }
@@ -29,7 +29,7 @@ expect.extend({
29
29
  try {
30
30
  await transaction.debug();
31
31
  const matcherHint = this.utils.matcherHint('.toFailRequireWith', undefined, match.toString(), { isNot: this.isNot });
32
- const message = () => `${matcherHint}\n\nContract function did not fail a require statement`;
32
+ const message = () => `${matcherHint}\n\nContract function did not fail a require statement.`;
33
33
  return { message, pass: false };
34
34
  }
35
35
  catch (transactionError) {
@@ -46,6 +46,18 @@ expect.extend({
46
46
  }
47
47
  }
48
48
  },
49
+ async toFailRequire(transaction) {
50
+ try {
51
+ await transaction.debug();
52
+ const message = () => 'Contract function did not fail a require statement.';
53
+ return { message, pass: false };
54
+ }
55
+ catch (transactionError) {
56
+ const receivedText = `Received string: ${this.utils.printReceived(transactionError?.message ?? '')}`;
57
+ const message = () => `Contract function failed a require statement.\n${receivedText}`;
58
+ return { message, pass: true };
59
+ }
60
+ },
49
61
  });
50
62
  export {};
51
63
  //# sourceMappingURL=JestExtensions.js.map
package/dist/utils.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { Transaction } from '@bitauth/libauth';
2
2
  import { Script } from '@cashscript/utils';
3
3
  import { Utxo, Output, LibauthOutput, TokenDetails, AddressType } from './interfaces.js';
4
- import { FailedTransactionError } from './Errors.js';
5
4
  export declare function validateOutput(output: Output): void;
6
5
  export declare function calculateDust(output: Output): number;
7
6
  export declare function getOutputSize(output: Output): number;
@@ -14,7 +13,6 @@ export declare function getTxSizeWithoutInputs(outputs: Output[]): number;
14
13
  export declare function createInputScript(redeemScript: Script, encodedArgs: Uint8Array[], selector?: number, preimage?: Uint8Array): Uint8Array;
15
14
  export declare function createOpReturnOutput(opReturnData: string[]): Output;
16
15
  export declare function createSighashPreimage(transaction: Transaction, sourceOutputs: LibauthOutput[], inputIndex: number, coveredBytecode: Uint8Array, hashtype: number): Uint8Array;
17
- export declare function buildError(reason: string, debugStr?: string): FailedTransactionError;
18
16
  export declare function toRegExp(reasons: string[]): RegExp;
19
17
  export declare function scriptToAddress(script: Script, network: string, addressType: AddressType, tokenSupport: boolean): string;
20
18
  export declare function scriptToLockingBytecode(script: Script, addressType: AddressType): Uint8Array;
@@ -30,10 +28,10 @@ export declare function utxoTokenComparator(a: Utxo, b: Utxo): number;
30
28
  */
31
29
  export declare function addressToLockScript(address: string): Uint8Array;
32
30
  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;
31
+ export declare const randomUtxo: (defaults?: Partial<Utxo>) => Utxo;
32
+ export declare const randomToken: (defaults?: Partial<TokenDetails>) => TokenDetails;
33
+ export declare const randomNFT: (defaults?: Partial<TokenDetails>) => TokenDetails;
36
34
  export declare function findLastIndex<T>(array: Array<T>, predicate: (value: T, index: number, obj: T[]) => boolean): number;
37
35
  export declare const snakeCase: (str: string) => string;
38
- export declare const extendedStringify: (obj: any, spaces?: number | undefined) => string;
36
+ export declare const extendedStringify: (obj: any, spaces?: number) => string;
39
37
  export declare const zip: <T, U>(a: T[], b: U[]) => [T, U][];
package/dist/utils.js CHANGED
@@ -1,8 +1,8 @@
1
- import { cashAddressToLockingBytecode, decodeCashAddress, addressContentsToLockingBytecode, lockingBytecodeToCashAddress, binToHex, generateSigningSerializationBCH, utf8ToBin, hexToBin, flattenBinArray, LockingBytecodeType, encodeTransactionOutput, isHex, bigIntToCompactUint, AuthenticationErrorCommon, NonFungibleTokenCapability, bigIntToVmNumber, } from '@bitauth/libauth';
1
+ import { cashAddressToLockingBytecode, decodeCashAddress, addressContentsToLockingBytecode, lockingBytecodeToCashAddress, binToHex, generateSigningSerializationBCH, utf8ToBin, hexToBin, flattenBinArray, LockingBytecodeType, encodeTransactionOutput, isHex, bigIntToCompactUint, NonFungibleTokenCapability, bigIntToVmNumber, } from '@bitauth/libauth';
2
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
- import { OutputSatoshisTooSmallError, TokensToNonTokenAddressError, Reason, FailedTransactionError, FailedRequireError, FailedTimeCheckError, FailedSigCheckError, } from './Errors.js';
5
+ import { OutputSatoshisTooSmallError, TokensToNonTokenAddressError, } from './Errors.js';
6
6
  // ////////// PARAMETER VALIDATION ////////////////////////////////////////////
7
7
  export function validateOutput(output) {
8
8
  if (typeof output.to !== 'string')
@@ -135,40 +135,16 @@ 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, debugStr) {
139
- const require = [
140
- Reason.EVAL_FALSE, Reason.VERIFY, Reason.EQUALVERIFY, Reason.CHECKMULTISIGVERIFY,
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,
147
- ];
148
- const sigCheck = [
149
- Reason.SIG_COUNT, Reason.PUBKEY_COUNT, Reason.SIG_HASHTYPE, Reason.SIG_DER,
150
- Reason.SIG_HIGH_S, Reason.SIG_NULLFAIL, Reason.SIG_BADLENGTH, Reason.SIG_NONSCHNORR,
151
- AuthenticationErrorCommon.nonNullSignatureFailure,
152
- ];
153
- if (toRegExp(require).test(reason)) {
154
- return new FailedRequireError(reason, debugStr);
155
- }
156
- if (toRegExp(timeCheck).test(reason)) {
157
- return new FailedTimeCheckError(reason, debugStr);
158
- }
159
- if (toRegExp(sigCheck).test(reason)) {
160
- return new FailedSigCheckError(reason, debugStr);
161
- }
162
- return new FailedTransactionError(reason, debugStr);
163
- }
164
138
  export function toRegExp(reasons) {
165
139
  return new RegExp(reasons.join('|').replace(/\(/g, '\\(').replace(/\)/g, '\\)'));
166
140
  }
167
141
  export function scriptToAddress(script, network, addressType, tokenSupport) {
168
- const lockingBytecode = scriptToLockingBytecode(script, addressType);
142
+ const bytecode = scriptToLockingBytecode(script, addressType);
169
143
  const prefix = getNetworkPrefix(network);
170
- const address = lockingBytecodeToCashAddress(lockingBytecode, prefix, { tokenSupport });
171
- return address;
144
+ const result = lockingBytecodeToCashAddress({ bytecode, prefix, tokenSupport });
145
+ if (typeof result === 'string')
146
+ throw new Error(result);
147
+ return result.address;
172
148
  }
173
149
  export function scriptToLockingBytecode(script, addressType) {
174
150
  const scriptBytecode = scriptToBytecode(script);
@@ -247,7 +223,7 @@ function getPushDataOpcode(data) {
247
223
  return Uint8Array.from([byteLength]);
248
224
  if (byteLength < 256)
249
225
  return Uint8Array.from([0x4c, byteLength]);
250
- throw Error('Pushdata too large');
226
+ throw new Error('Pushdata too large');
251
227
  }
252
228
  const randomInt = () => BigInt(Math.floor(Math.random() * 10000));
253
229
  export const randomUtxo = (defaults) => ({
@@ -0,0 +1,5 @@
1
+ {
2
+ "type": "module",
3
+ "types": "../dist/test/JestExtensions.d.ts",
4
+ "main": "../dist/test/JestExtensions.js"
5
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cashscript",
3
- "version": "0.10.0-next.5",
3
+ "version": "0.10.0",
4
4
  "description": "Easily write and interact with Bitcoin Cash contracts",
5
5
  "keywords": [
6
6
  "bitcoin cash",
@@ -10,11 +10,11 @@
10
10
  ],
11
11
  "homepage": "https://cashscript.org",
12
12
  "bugs": {
13
- "url": "https://github.com/Bitcoin-com/cashscript/issues"
13
+ "url": "https://github.com/CashScript/cashscript/issues"
14
14
  },
15
15
  "repository": {
16
16
  "type": "git",
17
- "url": "git+https://github.com/Bitcoin-com/cashscript.git"
17
+ "url": "git+https://github.com/CashScript/cashscript.git"
18
18
  },
19
19
  "license": "MIT",
20
20
  "author": "Rosco Kalis <roscokalis@gmail.com>",
@@ -43,8 +43,8 @@
43
43
  "test": "NODE_OPTIONS='--experimental-vm-modules --no-warnings' jest"
44
44
  },
45
45
  "dependencies": {
46
- "@bitauth/libauth": "^2.0.0",
47
- "@cashscript/utils": "^0.10.0-next.5",
46
+ "@bitauth/libauth": "^3.0.0",
47
+ "@cashscript/utils": "^0.10.0",
48
48
  "bip68": "^1.0.4",
49
49
  "bitcoin-rpc-promise-retry": "^1.3.0",
50
50
  "delay": "^5.0.0",
@@ -59,7 +59,7 @@
59
59
  "bip39": "^3.0.4",
60
60
  "eslint": "^8.54.0",
61
61
  "jest": "^29.4.1",
62
- "typescript": "^4.1.5"
62
+ "typescript": "^5.5.4"
63
63
  },
64
- "gitHead": "3d6611410e8c7ed9d760071a8c639e91c2cbb477"
64
+ "gitHead": "cd3031b60dc4ca2d2351608dfd838a50bcc7bbb9"
65
65
  }