cashscript 0.7.6 → 0.8.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +2 -6
  2. package/dist/{main/Argument.d.ts → Argument.d.ts} +1 -1
  3. package/dist/{module/Argument.js → Argument.js} +1 -1
  4. package/dist/{module/Contract.d.ts → Contract.d.ts} +8 -6
  5. package/dist/{module/Contract.js → Contract.js} +15 -25
  6. package/dist/{main/Errors.d.ts → Errors.d.ts} +4 -1
  7. package/dist/{module/Errors.js → Errors.js} +7 -3
  8. package/dist/{main/SignatureTemplate.d.ts → SignatureTemplate.d.ts} +2 -3
  9. package/dist/{module/SignatureTemplate.js → SignatureTemplate.js} +4 -5
  10. package/dist/{module/Transaction.d.ts → Transaction.d.ts} +7 -5
  11. package/dist/Transaction.js +352 -0
  12. package/dist/constants.d.ts +2 -0
  13. package/dist/constants.js +3 -0
  14. package/dist/{main/index.d.ts → index.d.ts} +1 -1
  15. package/dist/{module/index.js → index.js} +2 -3
  16. package/dist/{module/interfaces.d.ts → interfaces.d.ts} +33 -6
  17. package/dist/{module/interfaces.js → interfaces.js} +0 -2
  18. package/dist/{module/network → network}/BitcoinRpcNetworkProvider.d.ts +2 -3
  19. package/dist/network/BitcoinRpcNetworkProvider.js +29 -0
  20. package/dist/{module/network → network}/ElectrumNetworkProvider.js +53 -72
  21. package/dist/network/FullStackNetworkProvider.js +33 -0
  22. package/dist/{main/network → network}/index.d.ts +0 -1
  23. package/dist/{module/network → network}/index.js +0 -1
  24. package/dist/{main/utils.d.ts → utils.d.ts} +10 -6
  25. package/dist/{module/utils.js → utils.js} +90 -46
  26. package/package.json +18 -16
  27. package/dist/main/Argument.js +0 -60
  28. package/dist/main/Contract.d.ts +0 -23
  29. package/dist/main/Contract.js +0 -87
  30. package/dist/main/Errors.js +0 -84
  31. package/dist/main/SignatureTemplate.js +0 -45
  32. package/dist/main/Transaction.d.ts +0 -39
  33. package/dist/main/Transaction.js +0 -258
  34. package/dist/main/constants.d.ts +0 -5
  35. package/dist/main/constants.js +0 -9
  36. package/dist/main/index.js +0 -50
  37. package/dist/main/interfaces.d.ts +0 -43
  38. package/dist/main/interfaces.js +0 -32
  39. package/dist/main/network/BitboxNetworkProvider.d.ts +0 -26
  40. package/dist/main/network/BitboxNetworkProvider.js +0 -40
  41. package/dist/main/network/BitcoinRpcNetworkProvider.d.ts +0 -41
  42. package/dist/main/network/BitcoinRpcNetworkProvider.js +0 -49
  43. package/dist/main/network/ElectrumNetworkProvider.js +0 -162
  44. package/dist/main/network/FullStackNetworkProvider.js +0 -55
  45. package/dist/main/network/NetworkProvider.js +0 -3
  46. package/dist/main/network/index.js +0 -15
  47. package/dist/main/utils.js +0 -205
  48. package/dist/module/Argument.d.ts +0 -3
  49. package/dist/module/Errors.d.ts +0 -66
  50. package/dist/module/SignatureTemplate.d.ts +0 -15
  51. package/dist/module/Transaction.js +0 -251
  52. package/dist/module/constants.d.ts +0 -5
  53. package/dist/module/constants.js +0 -6
  54. package/dist/module/index.d.ts +0 -10
  55. package/dist/module/network/BitboxNetworkProvider.d.ts +0 -26
  56. package/dist/module/network/BitboxNetworkProvider.js +0 -37
  57. package/dist/module/network/BitcoinRpcNetworkProvider.js +0 -46
  58. package/dist/module/network/ElectrumNetworkProvider.d.ts +0 -19
  59. package/dist/module/network/FullStackNetworkProvider.d.ts +0 -40
  60. package/dist/module/network/FullStackNetworkProvider.js +0 -52
  61. package/dist/module/network/NetworkProvider.d.ts +0 -31
  62. package/dist/module/network/index.d.ts +0 -5
  63. package/dist/module/utils.d.ts +0 -26
  64. /package/dist/{main/network → network}/ElectrumNetworkProvider.d.ts +0 -0
  65. /package/dist/{main/network → network}/FullStackNetworkProvider.d.ts +0 -0
  66. /package/dist/{main/network → network}/NetworkProvider.d.ts +0 -0
  67. /package/dist/{module/network → network}/NetworkProvider.js +0 -0
@@ -1,9 +1,11 @@
1
- import { Transaction } from '@bitauth/libauth';
1
+ import type { Transaction } from '@bitauth/libauth';
2
+ import type { NetworkProvider } from './network/index.js';
2
3
  import type SignatureTemplate from './SignatureTemplate.js';
3
4
  export interface Utxo {
4
5
  txid: string;
5
6
  vout: number;
6
- satoshis: number;
7
+ satoshis: bigint;
8
+ token?: TokenDetails;
7
9
  }
8
10
  export interface SignableUtxo extends Utxo {
9
11
  template: SignatureTemplate;
@@ -11,11 +13,34 @@ export interface SignableUtxo extends Utxo {
11
13
  export declare function isSignableUtxo(utxo: Utxo): utxo is SignableUtxo;
12
14
  export interface Recipient {
13
15
  to: string;
14
- amount: number;
16
+ amount: bigint;
17
+ token?: TokenDetails;
15
18
  }
16
19
  export interface Output {
17
20
  to: string | Uint8Array;
18
- amount: number;
21
+ amount: bigint;
22
+ token?: TokenDetails;
23
+ }
24
+ export interface TokenDetails {
25
+ amount: bigint;
26
+ category: string;
27
+ nft?: {
28
+ capability: 'none' | 'mutable' | 'minting';
29
+ commitment: string;
30
+ };
31
+ }
32
+ export interface LibauthOutput {
33
+ lockingBytecode: Uint8Array;
34
+ valueSatoshis: bigint;
35
+ token?: LibauthTokenDetails;
36
+ }
37
+ export interface LibauthTokenDetails {
38
+ amount: bigint;
39
+ category: Uint8Array;
40
+ nft?: {
41
+ capability: 'none' | 'mutable' | 'minting';
42
+ commitment: Uint8Array;
43
+ };
19
44
  }
20
45
  export declare enum SignatureAlgorithm {
21
46
  ECDSA = 0,
@@ -32,8 +57,6 @@ export declare const Network: {
32
57
  TESTNET3: "testnet3";
33
58
  TESTNET4: "testnet4";
34
59
  CHIPNET: "chipnet";
35
- TESTNET: "testnet";
36
- STAGING: "staging";
37
60
  REGTEST: "regtest";
38
61
  };
39
62
  export declare type Network = (typeof Network)[keyof typeof Network];
@@ -41,3 +64,7 @@ export interface TransactionDetails extends Transaction {
41
64
  txid: string;
42
65
  hex: string;
43
66
  }
67
+ export interface ContractOptions {
68
+ provider?: NetworkProvider;
69
+ addressType?: 'p2sh20' | 'p2sh32';
70
+ }
@@ -21,8 +21,6 @@ export const Network = {
21
21
  TESTNET3: literal('testnet3'),
22
22
  TESTNET4: literal('testnet4'),
23
23
  CHIPNET: literal('chipnet'),
24
- TESTNET: literal('testnet'),
25
- STAGING: literal('staging'),
26
24
  REGTEST: literal('regtest'),
27
25
  };
28
26
  //# sourceMappingURL=interfaces.js.map
@@ -1,6 +1,5 @@
1
1
  import { Utxo, Network } from '../interfaces.js';
2
2
  import NetworkProvider from './NetworkProvider.js';
3
- declare const RpcClientRetry: any;
4
3
  export default class BitcoinRpcNetworkProvider implements NetworkProvider {
5
4
  network: Network;
6
5
  private rpcClient;
@@ -9,7 +8,7 @@ export default class BitcoinRpcNetworkProvider implements NetworkProvider {
9
8
  getBlockHeight(): Promise<number>;
10
9
  getRawTransaction(txid: string): Promise<string>;
11
10
  sendRawTransaction(txHex: string): Promise<string>;
12
- getClient(): RpcClientRetry;
11
+ getClient(): IRpcClientRetry;
13
12
  }
14
13
  interface ListUnspentItem {
15
14
  txid: string;
@@ -24,7 +23,7 @@ interface ListUnspentItem {
24
23
  solvable: boolean;
25
24
  safe: boolean;
26
25
  }
27
- interface RpcClientRetry {
26
+ interface IRpcClientRetry {
28
27
  constructor(url: string, opts?: object): void;
29
28
  listUnspent(minConf?: number, maxConf?: number, addresses?: string[], includeUnsafe?: boolean, queryOptions?: object): Promise<ListUnspentItem[]>;
30
29
  getBlockCount(): Promise<number>;
@@ -0,0 +1,29 @@
1
+ const { default: RpcClientRetry } = await import('bitcoin-rpc-promise-retry');
2
+ export default class BitcoinRpcNetworkProvider {
3
+ constructor(network, url, opts) {
4
+ this.network = network;
5
+ this.rpcClient = new RpcClientRetry(url, opts);
6
+ }
7
+ async getUtxos(address) {
8
+ const result = await this.rpcClient.listUnspent(0, 9999999, [address]);
9
+ const utxos = result.map((utxo) => ({
10
+ txid: utxo.txid,
11
+ vout: utxo.vout,
12
+ satoshis: BigInt(utxo.amount * 1e8),
13
+ }));
14
+ return utxos;
15
+ }
16
+ async getBlockHeight() {
17
+ return this.rpcClient.getBlockCount();
18
+ }
19
+ async getRawTransaction(txid) {
20
+ return this.rpcClient.getRawTransaction(txid);
21
+ }
22
+ async sendRawTransaction(txHex) {
23
+ return this.rpcClient.sendRawTransaction(txHex);
24
+ }
25
+ getClient() {
26
+ return this.rpcClient;
27
+ }
28
+ }
29
+ //# sourceMappingURL=BitcoinRpcNetworkProvider.js.map
@@ -1,12 +1,3 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  import { binToHex } from '@bitauth/libauth';
11
2
  import { sha256 } from '@cashscript/utils';
12
3
  import { ElectrumCluster, ElectrumTransport, ClusterOrder, } from 'electrum-cash';
@@ -33,7 +24,7 @@ export default class ElectrumNetworkProvider {
33
24
  this.electrum.addServer('bch.loping.net', 50004, ElectrumTransport.WSS.Scheme, false);
34
25
  this.electrum.addServer('electrum.imaginary.cash', 50004, ElectrumTransport.WSS.Scheme, false);
35
26
  }
36
- else if (network === Network.TESTNET || network === Network.TESTNET3) {
27
+ else if (network === Network.TESTNET3) {
37
28
  // Initialise a 1-of-2 Electrum Cluster with 2 hardcoded servers
38
29
  this.electrum = new ElectrumCluster('CashScript Application', '1.4.1', 1, 2, ClusterOrder.PRIORITY);
39
30
  this.electrum.addServer('blackie.c3-soft.com', 60004, ElectrumTransport.WSS.Scheme, false);
@@ -41,7 +32,7 @@ export default class ElectrumNetworkProvider {
41
32
  // this.electrum.addServer('bch.loping.net', 60004, ElectrumTransport.WSS.Scheme, false);
42
33
  // this.electrum.addServer('testnet.imaginary.cash', 50004, ElectrumTransport.WSS.Scheme);
43
34
  }
44
- else if (network === Network.STAGING || network === Network.TESTNET4) {
35
+ else if (network === Network.TESTNET4) {
45
36
  this.electrum = new ElectrumCluster('CashScript Application', '1.4.1', 1, 1, ClusterOrder.PRIORITY);
46
37
  this.electrum.addServer('testnet4.imaginary.cash', 50004, ElectrumTransport.WSS.Scheme, false);
47
38
  }
@@ -53,74 +44,64 @@ export default class ElectrumNetworkProvider {
53
44
  throw new Error(`Tried to instantiate an ElectrumNetworkProvider for unsupported network ${network}`);
54
45
  }
55
46
  }
56
- getUtxos(address) {
57
- return __awaiter(this, void 0, void 0, function* () {
58
- const scripthash = addressToElectrumScriptHash(address);
59
- const result = yield this.performRequest('blockchain.scripthash.listunspent', scripthash);
60
- const utxos = result.map((utxo) => ({
61
- txid: utxo.tx_hash,
62
- vout: utxo.tx_pos,
63
- satoshis: utxo.value,
64
- height: utxo.height,
65
- }));
66
- return utxos;
67
- });
47
+ async getUtxos(address) {
48
+ const scripthash = addressToElectrumScriptHash(address);
49
+ const filteringOption = 'include_tokens';
50
+ const result = await this.performRequest('blockchain.scripthash.listunspent', scripthash, filteringOption);
51
+ const utxos = result.map((utxo) => ({
52
+ txid: utxo.tx_hash,
53
+ vout: utxo.tx_pos,
54
+ satoshis: BigInt(utxo.value),
55
+ token: utxo.token_data ? {
56
+ ...utxo.token_data,
57
+ amount: BigInt(utxo.token_data.amount),
58
+ } : undefined,
59
+ }));
60
+ return utxos;
68
61
  }
69
- getBlockHeight() {
70
- return __awaiter(this, void 0, void 0, function* () {
71
- const { height } = yield this.performRequest('blockchain.headers.subscribe');
72
- return height;
73
- });
62
+ async getBlockHeight() {
63
+ const { height } = await this.performRequest('blockchain.headers.subscribe');
64
+ return height;
74
65
  }
75
- getRawTransaction(txid) {
76
- return __awaiter(this, void 0, void 0, function* () {
77
- return yield this.performRequest('blockchain.transaction.get', txid);
78
- });
66
+ async getRawTransaction(txid) {
67
+ return await this.performRequest('blockchain.transaction.get', txid);
79
68
  }
80
- sendRawTransaction(txHex) {
81
- return __awaiter(this, void 0, void 0, function* () {
82
- return yield this.performRequest('blockchain.transaction.broadcast', txHex);
83
- });
69
+ async sendRawTransaction(txHex) {
70
+ return await this.performRequest('blockchain.transaction.broadcast', txHex);
84
71
  }
85
- connectCluster() {
86
- return __awaiter(this, void 0, void 0, function* () {
87
- try {
88
- return yield this.electrum.startup();
89
- }
90
- catch (e) {
91
- return [];
92
- }
93
- });
72
+ async connectCluster() {
73
+ try {
74
+ return await this.electrum.startup();
75
+ }
76
+ catch (e) {
77
+ return [];
78
+ }
94
79
  }
95
- disconnectCluster() {
96
- return __awaiter(this, void 0, void 0, function* () {
97
- return this.electrum.shutdown();
98
- });
80
+ async disconnectCluster() {
81
+ return this.electrum.shutdown();
99
82
  }
100
- performRequest(name, ...parameters) {
101
- return __awaiter(this, void 0, void 0, function* () {
102
- // Only connect the cluster when no concurrent requests are running
103
- if (this.shouldConnect()) {
104
- this.connectCluster();
105
- }
106
- this.concurrentRequests += 1;
107
- yield this.electrum.ready();
108
- let result;
109
- try {
110
- result = yield this.electrum.request(name, ...parameters);
111
- }
112
- finally {
113
- // Always disconnect the cluster, also if the request fails
114
- // as long as no other concurrent requests are running
115
- if (this.shouldDisconnect()) {
116
- yield this.disconnectCluster();
117
- }
83
+ async performRequest(name, ...parameters) {
84
+ // Only connect the cluster when no concurrent requests are running
85
+ if (this.shouldConnect()) {
86
+ this.connectCluster();
87
+ }
88
+ this.concurrentRequests += 1;
89
+ await this.electrum.ready();
90
+ let result;
91
+ try {
92
+ result = await this.electrum.request(name, ...parameters);
93
+ }
94
+ finally {
95
+ // Always disconnect the cluster, also if the request fails
96
+ // as long as no other concurrent requests are running
97
+ if (this.shouldDisconnect()) {
98
+ await this.disconnectCluster();
118
99
  }
119
- this.concurrentRequests -= 1;
120
- if (result instanceof Error)
121
- throw result;
122
- return result;
123
- });
100
+ }
101
+ this.concurrentRequests -= 1;
102
+ if (result instanceof Error)
103
+ throw result;
104
+ return result;
124
105
  }
125
106
  shouldConnect() {
126
107
  if (this.manualConnectionManagement)
@@ -0,0 +1,33 @@
1
+ export default class FullStackNetworkProvider {
2
+ /**
3
+ * @example
4
+ * const BCHJS = require("@psf/bch-js")
5
+ * let bchjs = new BCHJS({
6
+ * restURL: 'https://api.fullstack.cash/v3/',
7
+ * apiToken: 'eyJhbGciO...' // Your JWT token here.
8
+ * })
9
+ */
10
+ constructor(network, bchjs) {
11
+ this.network = network;
12
+ this.bchjs = bchjs;
13
+ }
14
+ async getUtxos(address) {
15
+ const result = await this.bchjs.Electrumx.utxo(address);
16
+ const utxos = (result.utxos ?? []).map((utxo) => ({
17
+ txid: utxo.tx_hash,
18
+ vout: utxo.tx_pos,
19
+ satoshis: BigInt(utxo.value),
20
+ }));
21
+ return utxos;
22
+ }
23
+ async getBlockHeight() {
24
+ return this.bchjs.Blockchain.getBlockCount();
25
+ }
26
+ async getRawTransaction(txid) {
27
+ return this.bchjs.RawTransactions.getRawTransaction(txid);
28
+ }
29
+ async sendRawTransaction(txHex) {
30
+ return this.bchjs.RawTransactions.sendRawTransaction(txHex);
31
+ }
32
+ }
33
+ //# sourceMappingURL=FullStackNetworkProvider.js.map
@@ -1,5 +1,4 @@
1
1
  export { default as NetworkProvider } from './NetworkProvider.js';
2
- export { default as BitboxNetworkProvider } from './BitboxNetworkProvider.js';
3
2
  export { default as BitcoinRpcNetworkProvider } from './BitcoinRpcNetworkProvider.js';
4
3
  export { default as ElectrumNetworkProvider } from './ElectrumNetworkProvider.js';
5
4
  export { default as FullStackNetworkProvider } from './FullStackNetworkProvider.js';
@@ -1,4 +1,3 @@
1
- export { default as BitboxNetworkProvider } from './BitboxNetworkProvider.js';
2
1
  export { default as BitcoinRpcNetworkProvider } from './BitcoinRpcNetworkProvider.js';
3
2
  export { default as ElectrumNetworkProvider } from './ElectrumNetworkProvider.js';
4
3
  export { default as FullStackNetworkProvider } from './FullStackNetworkProvider.js';
@@ -1,20 +1,24 @@
1
1
  import { Transaction } from '@bitauth/libauth';
2
2
  import { Script } from '@cashscript/utils';
3
- import { Utxo, Output, Recipient } from './interfaces.js';
3
+ import { Utxo, Output, Recipient, LibauthOutput } from './interfaces.js';
4
4
  import { FailedTransactionError } from './Errors.js';
5
5
  export declare function validateRecipient(recipient: Recipient): void;
6
+ export declare function calculateDust(recipient: Recipient): number;
7
+ export declare function getOutputSize(output: Output): number;
8
+ export declare function encodeOutput(output: Output): Uint8Array;
9
+ export declare function cashScriptOutputToLibauthOutput(output: Output): LibauthOutput;
10
+ export declare function libauthOutputToCashScriptOutput(output: LibauthOutput): Output;
6
11
  export declare function getInputSize(inputScript: Uint8Array): number;
7
12
  export declare function getPreimageSize(script: Uint8Array): number;
8
13
  export declare function getTxSizeWithoutInputs(outputs: Output[]): number;
9
14
  export declare function createInputScript(redeemScript: Script, encodedArgs: Uint8Array[], selector?: number, preimage?: Uint8Array): Uint8Array;
10
15
  export declare function createOpReturnOutput(opReturnData: string[]): Output;
11
- export declare function createSighashPreimage(transaction: Transaction, input: {
12
- satoshis: number;
13
- }, inputIndex: number, coveredBytecode: Uint8Array, hashtype: number): Uint8Array;
16
+ export declare function createSighashPreimage(transaction: Transaction, inputs: Utxo[], inputIndex: number, coveredBytecode: Uint8Array, hashtype: number): Uint8Array;
14
17
  export declare function buildError(reason: string, meepStr: string): FailedTransactionError;
15
18
  export declare function meep(tx: any, utxos: Utxo[], script: Script): string;
16
- export declare function scriptToAddress(script: Script, network: string): string;
17
- export declare function scriptToLockingBytecode(script: Script): Uint8Array;
19
+ export declare function scriptToAddress(script: Script, network: string, addressType: 'p2sh20' | 'p2sh32', tokenSupport: boolean): string;
20
+ export declare function scriptToLockingBytecode(script: Script, addressType: 'p2sh20' | 'p2sh32'): Uint8Array;
21
+ export declare function utxoComparator(a: Utxo, b: Utxo): number;
18
22
  /**
19
23
  * Helper function to convert an address to a locking script
20
24
  *
@@ -1,13 +1,67 @@
1
- import { cashAddressToLockingBytecode, AddressType, addressContentsToLockingBytecode, lockingBytecodeToCashAddress, binToHex, createTransactionContextCommon, bigIntToBinUint64LE, generateSigningSerializationBCH, utf8ToBin, hexToBin, flattenBinArray, } from '@bitauth/libauth';
2
- import { encodeInt, hash160, Op, scriptToBytecode, sha256, } from '@cashscript/utils';
1
+ import { cashAddressToLockingBytecode, decodeCashAddress, addressContentsToLockingBytecode, lockingBytecodeToCashAddress, binToHex, generateSigningSerializationBCH, utf8ToBin, hexToBin, flattenBinArray, LockingBytecodeType, encodeTransactionOutput, } from '@bitauth/libauth';
2
+ import { encodeInt, hash160, hash256, Op, scriptToBytecode, } from '@cashscript/utils';
3
3
  import { Network, } from './interfaces.js';
4
- import { P2PKH_OUTPUT_SIZE, VERSION_SIZE, LOCKTIME_SIZE, DUST_LIMIT, } from './constants.js';
5
- import { OutputSatoshisTooSmallError, Reason, FailedTransactionError, FailedRequireError, FailedTimeCheckError, FailedSigCheckError, } from './Errors.js';
4
+ import { VERSION_SIZE, LOCKTIME_SIZE } from './constants.js';
5
+ import { OutputSatoshisTooSmallError, TokensToNonTokenAddressError, Reason, FailedTransactionError, FailedRequireError, FailedTimeCheckError, FailedSigCheckError, } from './Errors.js';
6
6
  // ////////// PARAMETER VALIDATION ////////////////////////////////////////////
7
7
  export function validateRecipient(recipient) {
8
- if (recipient.amount < DUST_LIMIT) {
9
- throw new OutputSatoshisTooSmallError(recipient.amount);
8
+ const minimumAmount = calculateDust(recipient);
9
+ if (recipient.amount < minimumAmount) {
10
+ throw new OutputSatoshisTooSmallError(recipient.amount, BigInt(minimumAmount));
10
11
  }
12
+ if (recipient.token) {
13
+ if (!isTokenAddress(recipient.to)) {
14
+ throw new TokensToNonTokenAddressError(recipient.to);
15
+ }
16
+ }
17
+ }
18
+ export function calculateDust(recipient) {
19
+ const outputSize = getOutputSize(recipient);
20
+ // Formula used to calculate the minimum allowed output
21
+ const dustAmount = 444 + outputSize * 3;
22
+ return dustAmount;
23
+ }
24
+ export function getOutputSize(output) {
25
+ const encodedOutput = encodeOutput(output);
26
+ return encodedOutput.byteLength;
27
+ }
28
+ export function encodeOutput(output) {
29
+ return encodeTransactionOutput(cashScriptOutputToLibauthOutput(output));
30
+ }
31
+ export function cashScriptOutputToLibauthOutput(output) {
32
+ return {
33
+ lockingBytecode: typeof output.to === 'string' ? addressToLockScript(output.to) : output.to,
34
+ valueSatoshis: output.amount,
35
+ token: output.token && {
36
+ ...output.token,
37
+ category: hexToBin(output.token.category),
38
+ nft: output.token.nft && {
39
+ ...output.token.nft,
40
+ commitment: hexToBin(output.token.nft.commitment),
41
+ },
42
+ },
43
+ };
44
+ }
45
+ export function libauthOutputToCashScriptOutput(output) {
46
+ return {
47
+ to: output.lockingBytecode,
48
+ amount: output.valueSatoshis,
49
+ token: output.token && {
50
+ ...output.token,
51
+ category: binToHex(output.token.category),
52
+ nft: output.token.nft && {
53
+ ...output.token.nft,
54
+ commitment: binToHex(output.token.nft.commitment),
55
+ },
56
+ },
57
+ };
58
+ }
59
+ function isTokenAddress(address) {
60
+ const result = decodeCashAddress(address);
61
+ if (typeof result === 'string')
62
+ throw new Error(result);
63
+ const supportsTokens = (result.type === 'p2pkhWithTokens' || result.type === 'p2shWithTokens');
64
+ return supportsTokens;
11
65
  }
12
66
  // ////////// SIZE CALCULATIONS ///////////////////////////////////////////////
13
67
  export function getInputSize(inputScript) {
@@ -36,15 +90,9 @@ export function getTxSizeWithoutInputs(outputs) {
36
90
  // Script (?)*
37
91
  // LockTime (4B)
38
92
  let size = VERSION_SIZE + LOCKTIME_SIZE;
39
- size += outputs.reduce((acc, output) => {
40
- if (typeof output.to === 'string') {
41
- return acc + P2PKH_OUTPUT_SIZE;
42
- }
43
- // Size of an OP_RETURN output = byteLength + 8 (amount) + 2 (scriptSize)
44
- return acc + output.to.byteLength + 8 + 2;
45
- }, 0);
93
+ size += outputs.reduce((acc, output) => acc + getOutputSize(output), 0);
46
94
  // Add tx-out count (accounting for a potential change output)
47
- size += encodeInt(outputs.length + 1).byteLength;
95
+ size += encodeInt(BigInt(outputs.length + 1)).byteLength;
48
96
  return size;
49
97
  }
50
98
  // ////////// BUILD OBJECTS ///////////////////////////////////////////////////
@@ -54,7 +102,7 @@ export function createInputScript(redeemScript, encodedArgs, selector, preimage)
54
102
  if (preimage !== undefined)
55
103
  unlockScript.push(preimage);
56
104
  if (selector !== undefined)
57
- unlockScript.push(encodeInt(selector));
105
+ unlockScript.push(encodeInt(BigInt(selector)));
58
106
  // Create input script and compile it to bytecode
59
107
  const inputScript = [...unlockScript, scriptToBytecode(redeemScript)];
60
108
  return scriptToBytecode(inputScript);
@@ -64,35 +112,25 @@ export function createOpReturnOutput(opReturnData) {
64
112
  Op.OP_RETURN,
65
113
  ...opReturnData.map((output) => toBin(output)),
66
114
  ];
67
- return { to: encodeNullDataScript(script), amount: 0 };
115
+ return { to: encodeNullDataScript(script), amount: 0n };
68
116
  }
69
117
  function toBin(output) {
70
118
  const data = output.replace(/^0x/, '');
71
119
  const encode = data === output ? utf8ToBin : hexToBin;
72
120
  return encode(data);
73
121
  }
74
- export function createSighashPreimage(transaction, input, inputIndex, coveredBytecode, hashtype) {
75
- const state = createTransactionContextCommon({
76
- inputIndex,
77
- sourceOutput: { satoshis: bigIntToBinUint64LE(BigInt(input.satoshis)) },
78
- spendingTransaction: transaction,
79
- });
80
- const sighashPreimage = generateSigningSerializationBCH({
81
- correspondingOutput: state.correspondingOutput,
82
- coveredBytecode,
83
- forkId: new Uint8Array([0, 0, 0]),
84
- locktime: state.locktime,
85
- outpointIndex: state.outpointIndex,
86
- outpointTransactionHash: state.outpointTransactionHash,
87
- outputValue: state.outputValue,
88
- sequenceNumber: state.sequenceNumber,
89
- sha256: { hash: sha256 },
90
- signingSerializationType: new Uint8Array([hashtype]),
91
- transactionOutpoints: state.transactionOutpoints,
92
- transactionOutputs: state.transactionOutputs,
93
- transactionSequenceNumbers: state.transactionSequenceNumbers,
94
- version: 2,
122
+ export function createSighashPreimage(transaction, inputs, inputIndex, coveredBytecode, hashtype) {
123
+ const sourceOutputs = inputs.map((input) => {
124
+ const sourceOutput = {
125
+ amount: input.satoshis,
126
+ to: Uint8Array.of(),
127
+ token: input.token,
128
+ };
129
+ return cashScriptOutputToLibauthOutput(sourceOutput);
95
130
  });
131
+ const context = { inputIndex, sourceOutputs, transaction };
132
+ const signingSerializationType = new Uint8Array([hashtype]);
133
+ const sighashPreimage = generateSigningSerializationBCH(context, { coveredBytecode, signingSerializationType });
96
134
  return sighashPreimage;
97
135
  }
98
136
  export function buildError(reason, meepStr) {
@@ -121,21 +159,29 @@ function toRegExp(reasons) {
121
159
  }
122
160
  // ////////// MISC ////////////////////////////////////////////////////////////
123
161
  export function meep(tx, utxos, script) {
124
- const scriptPubkey = binToHex(scriptToLockingBytecode(script));
162
+ const scriptPubkey = binToHex(scriptToLockingBytecode(script, 'p2sh20'));
125
163
  return `meep debug --tx=${tx} --idx=0 --amt=${utxos[0].satoshis} --pkscript=${scriptPubkey}`;
126
164
  }
127
- export function scriptToAddress(script, network) {
128
- const lockingBytecode = scriptToLockingBytecode(script);
165
+ export function scriptToAddress(script, network, addressType, tokenSupport) {
166
+ const lockingBytecode = scriptToLockingBytecode(script, addressType);
129
167
  const prefix = getNetworkPrefix(network);
130
- const address = lockingBytecodeToCashAddress(lockingBytecode, prefix);
168
+ const address = lockingBytecodeToCashAddress(lockingBytecode, prefix, { tokenSupport });
131
169
  return address;
132
170
  }
133
- export function scriptToLockingBytecode(script) {
134
- const scriptHash = hash160(scriptToBytecode(script));
135
- const addressContents = { payload: scriptHash, type: AddressType.p2sh };
171
+ export function scriptToLockingBytecode(script, addressType) {
172
+ const scriptBytecode = scriptToBytecode(script);
173
+ const scriptHash = (addressType === 'p2sh20') ? hash160(scriptBytecode) : hash256(scriptBytecode);
174
+ const addressContents = { payload: scriptHash, type: LockingBytecodeType[addressType] };
136
175
  const lockingBytecode = addressContentsToLockingBytecode(addressContents);
137
176
  return lockingBytecode;
138
177
  }
178
+ export function utxoComparator(a, b) {
179
+ if (a.satoshis > b.satoshis)
180
+ return 1;
181
+ if (a.satoshis < b.satoshis)
182
+ return -1;
183
+ return 0;
184
+ }
139
185
  /**
140
186
  * Helper function to convert an address to a locking script
141
187
  *
@@ -153,9 +199,7 @@ export function getNetworkPrefix(network) {
153
199
  switch (network) {
154
200
  case Network.MAINNET:
155
201
  return 'bitcoincash';
156
- case Network.STAGING:
157
202
  case Network.TESTNET4:
158
- case Network.TESTNET:
159
203
  case Network.TESTNET3:
160
204
  case Network.CHIPNET:
161
205
  return 'bchtest';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cashscript",
3
- "version": "0.7.6",
3
+ "version": "0.8.0-next.1",
4
4
  "description": "Easily write and interact with Bitcoin Cash contracts",
5
5
  "keywords": [
6
6
  "bitcoin cash",
@@ -21,39 +21,41 @@
21
21
  "contributors": [
22
22
  "Gabriel Cardona <gabriel@bitcoin.com>"
23
23
  ],
24
- "main": "dist/main/index",
25
- "module": "dist/module/index",
26
- "types": "dist/module/index",
24
+ "main": "dist/index.js",
25
+ "types": "dist/index.d.ts",
26
+ "type": "module",
27
27
  "sideEffects": false,
28
28
  "directories": {
29
29
  "lib": "src",
30
30
  "test": "test"
31
31
  },
32
32
  "scripts": {
33
- "build": "npm run clean && npm run compile",
33
+ "build": "yarn clean && yarn compile",
34
+ "build:test": "yarn clean:test && yarn compile:test",
34
35
  "clean": "rm -rf ./dist",
35
- "compile": "npm run compile:main && npm run compile:module",
36
- "compile:main": "tsc -p tsconfig.build.main.json",
37
- "compile:module": "tsc -p tsconfig.build.module.json",
36
+ "clean:test": "rm -rf ./dist-test",
37
+ "compile": "tsc -p tsconfig.build.json",
38
+ "compile:test": "tsc -p tsconfig.test.json",
38
39
  "lint": "eslint . --ext .ts --ignore-path ../../.eslintignore",
39
- "prepare": "npm run build",
40
- "test": "jest --config=../../jest.config.js packages/cashscript"
40
+ "prepare": "yarn build",
41
+ "pretest": "yarn build:test",
42
+ "test": "NODE_OPTIONS='--experimental-vm-modules --no-warnings' jest"
41
43
  },
42
44
  "dependencies": {
43
- "@bitauth/libauth": "^1.18.1",
44
- "@cashscript/utils": "^0.7.6",
45
+ "@bitauth/libauth": "^2.0.0-alpha.8",
46
+ "@cashscript/utils": "^0.8.0-next.1",
45
47
  "bip68": "^1.0.4",
46
48
  "bitcoin-rpc-promise-retry": "^1.3.0",
47
49
  "delay": "^5.0.0",
48
50
  "electrum-cash": "^2.0.10"
49
51
  },
50
52
  "devDependencies": {
53
+ "@jest/globals": "^29.4.1",
51
54
  "@psf/bch-js": "^4.15.0",
52
- "bitbox-sdk": "^8.11.2",
55
+ "bip39": "^3.0.4",
53
56
  "eslint": "^7.20.0",
54
- "jest": "^26.6.3",
55
- "ts-jest": "^26.5.1",
57
+ "jest": "^29.4.1",
56
58
  "typescript": "^4.1.5"
57
59
  },
58
- "gitHead": "c2daf1d80579e776b28270362041152ab0ac8898"
60
+ "gitHead": "77c621fb963cc8e8951faebae53267d3520b7fe9"
59
61
  }