cashscript 0.10.0-next.4 → 0.10.0-next.6

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
@@ -8,7 +8,7 @@
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,3 +1,9 @@
1
+ import { AbiFunction, Artifact } from '@cashscript/utils';
1
2
  import SignatureTemplate from './SignatureTemplate.js';
2
3
  export declare type Argument = bigint | boolean | string | Uint8Array | SignatureTemplate;
3
- export declare function encodeArgument(argument: Argument, typeStr: 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;
package/dist/Argument.js CHANGED
@@ -39,7 +39,7 @@ export function encodeArgument(argument, typeStr) {
39
39
  if (type === PrimitiveType.SIG && argument.byteLength !== 0) {
40
40
  type = new BytesType(65);
41
41
  }
42
- // Redefine SIG as a bytes64 so it is included in the size checks below
42
+ // Redefine DATASIG as a bytes64 so it is included in the size checks below
43
43
  // Note that ONLY Schnorr signatures are accepted
44
44
  if (type === PrimitiveType.DATASIG && argument.byteLength !== 0) {
45
45
  type = new BytesType(64);
@@ -50,4 +50,24 @@ export function encodeArgument(argument, typeStr) {
50
50
  }
51
51
  return argument;
52
52
  }
53
+ export const encodeConstructorArguments = (artifact, constructorArgs, encodeFunction = encodeArgument) => {
54
+ // Check there's no signature templates in the constructor
55
+ if (constructorArgs.some((arg) => arg instanceof SignatureTemplate)) {
56
+ throw new Error('Cannot use signatures in constructor');
57
+ }
58
+ const encodedArgs = constructorArgs
59
+ .map((arg, i) => encodeFunction(arg, artifact.constructorInputs[i].type));
60
+ return encodedArgs;
61
+ };
62
+ export const encodeFunctionArguments = (abiFunction, functionArgs, encodeFunction = encodeArgument) => {
63
+ const encodedArgs = functionArgs.map((arg, i) => encodeFunction(arg, abiFunction.inputs[i].type));
64
+ return encodedArgs;
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
+ }
53
73
  //# sourceMappingURL=Argument.js.map
@@ -1,11 +1,10 @@
1
1
  import { Artifact, Script } from '@cashscript/utils';
2
2
  import { Transaction } from './Transaction.js';
3
3
  import { Argument } from './Argument.js';
4
- import { Unlocker, ContractOptions, Utxo } from './interfaces.js';
4
+ import { Unlocker, ContractOptions, Utxo, AddressType } from './interfaces.js';
5
5
  import NetworkProvider from './network/NetworkProvider.js';
6
6
  export declare class Contract {
7
7
  artifact: Artifact;
8
- constructorArgs: Argument[];
9
8
  private options?;
10
9
  name: string;
11
10
  address: string;
@@ -17,7 +16,8 @@ export declare class Contract {
17
16
  unlock: Record<string, ContractUnlocker>;
18
17
  redeemScript: Script;
19
18
  provider: NetworkProvider;
20
- addressType: 'p2sh20' | 'p2sh32';
19
+ addressType: AddressType;
20
+ encodedConstructorArgs: Uint8Array[];
21
21
  constructor(artifact: Artifact, constructorArgs: Argument[], options?: ContractOptions | undefined);
22
22
  getBalance(): Promise<bigint>;
23
23
  getUtxos(): Promise<Utxo[]>;
package/dist/Contract.js CHANGED
@@ -1,14 +1,13 @@
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 } from './Argument.js';
4
+ import { encodeArgument, 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';
8
8
  export class Contract {
9
9
  constructor(artifact, constructorArgs, options) {
10
10
  this.artifact = artifact;
11
- this.constructorArgs = constructorArgs;
12
11
  this.options = options;
13
12
  this.provider = this.options?.provider ?? new ElectrumNetworkProvider();
14
13
  this.addressType = this.options?.addressType ?? 'p2sh32';
@@ -17,17 +16,11 @@ export class Contract {
17
16
  throw new Error('Invalid or incomplete artifact provided');
18
17
  }
19
18
  if (artifact.constructorInputs.length !== constructorArgs.length) {
20
- 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}`);
21
20
  }
22
21
  // Encode arguments (this also performs type checking)
23
- const encodedArgs = constructorArgs
24
- .map((arg, i) => encodeArgument(arg, artifact.constructorInputs[i].type))
25
- .reverse();
26
- // Check there's no signature templates in the constructor
27
- if (encodedArgs.some((arg) => arg instanceof SignatureTemplate)) {
28
- throw new Error('Cannot use signatures in constructor');
29
- }
30
- this.redeemScript = generateRedeemScript(asmToScript(this.artifact.bytecode), encodedArgs);
22
+ this.encodedConstructorArgs = encodeConstructorArguments(artifact, constructorArgs);
23
+ this.redeemScript = generateRedeemScript(asmToScript(this.artifact.bytecode), this.encodedConstructorArgs);
31
24
  // Populate the functions object with the contract's functions
32
25
  // (with a special case for single function, which has no "function selector")
33
26
  this.functions = {};
@@ -69,17 +62,19 @@ export class Contract {
69
62
  createFunction(abiFunction, selector) {
70
63
  return (...args) => {
71
64
  if (abiFunction.inputs.length !== args.length) {
72
- 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}`);
73
66
  }
74
67
  // Encode passed args (this also performs type checking)
75
- const encodedArgs = args
76
- .map((arg, i) => encodeArgument(arg, abiFunction.inputs[i].type));
68
+ const encodedArgs = encodeFunctionArguments(abiFunction, args);
77
69
  const unlocker = this.createUnlocker(abiFunction, selector)(...args);
78
70
  return new Transaction(this, unlocker, abiFunction, encodedArgs, selector);
79
71
  };
80
72
  }
81
73
  createUnlocker(abiFunction, selector) {
82
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
+ }
83
78
  const bytecode = scriptToBytecode(this.redeemScript);
84
79
  const encodedArgs = args
85
80
  .map((arg, i) => encodeArgument(arg, abiFunction.inputs[i].type));
package/dist/Errors.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Type } from '@cashscript/utils';
1
+ import { RequireStatement, Type } from '@cashscript/utils';
2
2
  export declare class TypeError extends Error {
3
3
  constructor(actual: string, expected: Type);
4
4
  }
@@ -10,16 +10,18 @@ export declare class TokensToNonTokenAddressError extends Error {
10
10
  }
11
11
  export declare class FailedTransactionError extends Error {
12
12
  reason: string;
13
- debugStr?: string | undefined;
14
- constructor(reason: string, debugStr?: string | undefined);
13
+ bitauthUri?: string | undefined;
14
+ constructor(reason: string, bitauthUri?: string | undefined);
15
15
  }
16
- export declare class FailedRequireError extends FailedTransactionError {
16
+ export declare class FailedRequireError extends Error {
17
+ contractName: string;
18
+ requireStatement: RequireStatement;
19
+ inputIndex: number;
20
+ libauthErrorMessage?: string | undefined;
21
+ bitauthUri?: string;
22
+ constructor(contractName: string, requireStatement: RequireStatement, inputIndex: number, libauthErrorMessage?: string | undefined);
17
23
  }
18
- export declare class FailedTimeCheckError extends FailedTransactionError {
19
- }
20
- export declare class FailedSigCheckError extends FailedTransactionError {
21
- }
22
- export declare enum Reason {
24
+ export declare enum NodeErrorReason {
23
25
  EVAL_FALSE = "Script evaluated without error but finished with a false/empty top stack element",
24
26
  VERIFY = "Script failed an OP_VERIFY operation",
25
27
  EQUALVERIFY = "Script failed an OP_EQUALVERIFY operation",
package/dist/Errors.js CHANGED
@@ -14,66 +14,72 @@ export class TokensToNonTokenAddressError extends Error {
14
14
  }
15
15
  }
16
16
  export class FailedTransactionError extends Error {
17
- constructor(reason, debugStr) {
18
- super(`Transaction failed with reason: ${reason}${debugStr ? `\n\n${debugStr}` : ''}`);
17
+ constructor(reason, bitauthUri) {
18
+ super(`${reason}\n\nBitauth URI: ${bitauthUri}`);
19
19
  this.reason = reason;
20
- this.debugStr = debugStr;
20
+ this.bitauthUri = bitauthUri;
21
21
  }
22
22
  }
23
- export class FailedRequireError extends FailedTransactionError {
24
- }
25
- export class FailedTimeCheckError extends FailedTransactionError {
26
- }
27
- export class FailedSigCheckError extends FailedTransactionError {
23
+ // TODO: Add tests for some non-require evaluation errors (e.g. invalid op_split range)
24
+ export class FailedRequireError extends Error {
25
+ constructor(contractName, requireStatement, inputIndex, libauthErrorMessage) {
26
+ const baseMessage = `${contractName}.cash:${requireStatement.line} Require statement failed at line ${requireStatement.line}`;
27
+ const fullMessage = `${baseMessage} with the following message: ${requireStatement.message}`;
28
+ super(requireStatement.message ? fullMessage : baseMessage);
29
+ this.contractName = contractName;
30
+ this.requireStatement = requireStatement;
31
+ this.inputIndex = inputIndex;
32
+ this.libauthErrorMessage = libauthErrorMessage;
33
+ }
28
34
  }
29
35
  // 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 = {}));
36
+ export var NodeErrorReason;
37
+ (function (NodeErrorReason) {
38
+ NodeErrorReason["EVAL_FALSE"] = "Script evaluated without error but finished with a false/empty top stack element";
39
+ NodeErrorReason["VERIFY"] = "Script failed an OP_VERIFY operation";
40
+ NodeErrorReason["EQUALVERIFY"] = "Script failed an OP_EQUALVERIFY operation";
41
+ NodeErrorReason["CHECKMULTISIGVERIFY"] = "Script failed an OP_CHECKMULTISIGVERIFY operation";
42
+ NodeErrorReason["CHECKSIGVERIFY"] = "Script failed an OP_CHECKSIGVERIFY operation";
43
+ NodeErrorReason["CHECKDATASIGVERIFY"] = "Script failed an OP_CHECKDATASIGVERIFY operation";
44
+ NodeErrorReason["NUMEQUALVERIFY"] = "Script failed an OP_NUMEQUALVERIFY operation";
45
+ NodeErrorReason["SCRIPT_SIZE"] = "Script is too big";
46
+ NodeErrorReason["PUSH_SIZE"] = "Push value size limit exceeded";
47
+ NodeErrorReason["OP_COUNT"] = "Operation limit exceeded";
48
+ NodeErrorReason["STACK_SIZE"] = "Stack size limit exceeded";
49
+ NodeErrorReason["SIG_COUNT"] = "Signature count negative or greater than pubkey count";
50
+ NodeErrorReason["PUBKEY_COUNT"] = "Pubkey count negative or limit exceeded";
51
+ NodeErrorReason["INVALID_OPERAND_SIZE"] = "Invalid operand size";
52
+ NodeErrorReason["INVALID_NUMBER_RANGE"] = "Given operand is not a number within the valid range";
53
+ NodeErrorReason["IMPOSSIBLE_ENCODING"] = "The requested encoding is impossible to satisfy";
54
+ NodeErrorReason["INVALID_SPLIT_RANGE"] = "Invalid OP_SPLIT range";
55
+ NodeErrorReason["INVALID_BIT_COUNT"] = "Invalid number of bit set in OP_CHECKMULTISIG";
56
+ NodeErrorReason["BAD_OPCODE"] = "Opcode missing or not understood";
57
+ NodeErrorReason["DISABLED_OPCODE"] = "Attempted to use a disabled opcode";
58
+ NodeErrorReason["INVALID_STACK_OPERATION"] = "Operation not valid with the current stack size";
59
+ NodeErrorReason["INVALID_ALTSTACK_OPERATION"] = "Operation not valid with the current altstack size";
60
+ NodeErrorReason["OP_RETURN"] = "OP_RETURN was encountered";
61
+ NodeErrorReason["UNBALANCED_CONDITIONAL"] = "Invalid OP_IF construction";
62
+ NodeErrorReason["DIV_BY_ZERO"] = "Division by zero error";
63
+ NodeErrorReason["MOD_BY_ZERO"] = "Modulo by zero error";
64
+ NodeErrorReason["INVALID_BITFIELD_SIZE"] = "Bitfield of unexpected size error";
65
+ NodeErrorReason["INVALID_BIT_RANGE"] = "Bitfield's bit out of the expected range";
66
+ NodeErrorReason["NEGATIVE_LOCKTIME"] = "Negative locktime";
67
+ NodeErrorReason["UNSATISFIED_LOCKTIME"] = "Locktime requirement not satisfied";
68
+ NodeErrorReason["SIG_HASHTYPE"] = "Signature hash type missing or not understood";
69
+ NodeErrorReason["SIG_DER"] = "Non-canonical DER signature";
70
+ NodeErrorReason["MINIMALDATA"] = "Data push larger than necessary";
71
+ NodeErrorReason["SIG_PUSHONLY"] = "Only push operators allowed in signature scripts";
72
+ NodeErrorReason["SIG_HIGH_S"] = "Non-canonical signature: S value is unnecessarily high";
73
+ NodeErrorReason["MINIMALIF"] = "OP_IF/NOTIF argument must be minimal";
74
+ NodeErrorReason["SIG_NULLFAIL"] = "Signature must be zero for failed CHECK(MULTI)SIG operation";
75
+ NodeErrorReason["SIG_BADLENGTH"] = "Signature cannot be 65 bytes in CHECKMULTISIG";
76
+ NodeErrorReason["SIG_NONSCHNORR"] = "Only Schnorr signatures allowed in this operation";
77
+ NodeErrorReason["DISCOURAGE_UPGRADABLE_NOPS"] = "NOPx reserved for soft-fork upgrades";
78
+ NodeErrorReason["PUBKEYTYPE"] = "Public key is neither compressed or uncompressed";
79
+ NodeErrorReason["CLEANSTACK"] = "Script did not clean its stack";
80
+ NodeErrorReason["NONCOMPRESSED_PUBKEY"] = "Using non-compressed public key";
81
+ NodeErrorReason["ILLEGAL_FORKID"] = "Illegal use of SIGHASH_FORKID";
82
+ NodeErrorReason["MUST_USE_FORKID"] = "Signature must use SIGHASH_FORKID";
83
+ NodeErrorReason["UNKNOWN"] = "unknown error";
84
+ })(NodeErrorReason || (NodeErrorReason = {}));
79
85
  //# sourceMappingURL=Errors.js.map
@@ -1,8 +1,17 @@
1
1
  import { WalletTemplate } from '@bitauth/libauth';
2
2
  import { Transaction } from './Transaction.js';
3
- export declare const stringify: (any: any, spaces?: number | undefined) => string;
4
- export declare const buildTemplate: ({ transaction, transactionHex, }: {
3
+ interface BuildTemplateOptions {
5
4
  transaction: Transaction;
6
- transactionHex?: string | undefined;
7
- }) => Promise<WalletTemplate>;
5
+ transactionHex?: string;
6
+ }
7
+ export declare const buildTemplate: ({ transaction, transactionHex, }: BuildTemplateOptions) => Promise<WalletTemplate>;
8
8
  export declare const getBitauthUri: (template: WalletTemplate) => string;
9
+ export interface LibauthTemplateTokenDetails {
10
+ amount: string;
11
+ category: string;
12
+ nft?: {
13
+ capability: 'none' | 'mutable' | 'minting';
14
+ commitment: string;
15
+ };
16
+ }
17
+ export {};