cashscript 0.11.0-next.4 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Contract.d.ts +0 -1
- package/dist/Errors.js +3 -9
- package/dist/LibauthTemplate.js +2 -17
- package/dist/SignatureTemplate.d.ts +2 -2
- package/dist/Transaction.js +4 -2
- package/dist/TransactionBuilder.d.ts +4 -1
- package/dist/TransactionBuilder.js +40 -16
- package/dist/advanced/LibauthTemplate.d.ts +5 -5
- package/dist/advanced/LibauthTemplate.js +47 -34
- package/dist/debugging.js +9 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/interfaces.d.ts +11 -4
- package/dist/interfaces.js +12 -0
- package/dist/network/MockNetworkProvider.d.ts +2 -0
- package/dist/network/MockNetworkProvider.js +5 -1
- package/dist/test/JestExtensions.js +44 -12
- package/dist/utils.d.ts +2 -1
- package/dist/utils.js +11 -0
- package/dist/walletconnect-utils.d.ts +25 -0
- package/dist/walletconnect-utils.js +35 -0
- package/package.json +3 -3
package/dist/Contract.d.ts
CHANGED
package/dist/Errors.js
CHANGED
|
@@ -31,7 +31,8 @@ export class NoDebugInformationInArtifactError extends Error {
|
|
|
31
31
|
}
|
|
32
32
|
export class FailedTransactionError extends Error {
|
|
33
33
|
constructor(reason, bitauthUri) {
|
|
34
|
-
|
|
34
|
+
const warning = 'WARNING: it is unsafe to use this Bitauth URI when using real private keys as they are included in the transaction template';
|
|
35
|
+
super(`${reason}${bitauthUri ? `\n\n${warning}\n\nBitauth URI: ${bitauthUri}` : ''}`);
|
|
35
36
|
this.reason = reason;
|
|
36
37
|
this.bitauthUri = bitauthUri;
|
|
37
38
|
}
|
|
@@ -53,14 +54,7 @@ export class FailedTransactionEvaluationError extends FailedTransactionError {
|
|
|
53
54
|
}
|
|
54
55
|
export class FailedRequireError extends FailedTransactionError {
|
|
55
56
|
constructor(artifact, failingInstructionPointer, requireStatement, inputIndex, bitauthUri, libauthErrorMessage) {
|
|
56
|
-
|
|
57
|
-
if (!statement.includes('require')) {
|
|
58
|
-
statement = requireStatement.message
|
|
59
|
-
? `require(${statement}, "${requireStatement.message}")`
|
|
60
|
-
: `require(${statement})`;
|
|
61
|
-
// Sometimes in reconstructed multiline require statements, we get double commas
|
|
62
|
-
statement = statement.replace(/,,/g, ',');
|
|
63
|
-
}
|
|
57
|
+
const { statement, lineNumber } = getLocationDataForInstructionPointer(artifact, failingInstructionPointer);
|
|
64
58
|
const baseMessage = `${artifact.contractName}.cash:${lineNumber} Require statement failed at input ${inputIndex} in contract ${artifact.contractName}.cash at line ${lineNumber}`;
|
|
65
59
|
const baseMessageWithRequireMessage = `${baseMessage} with the following message: ${requireStatement.message}`;
|
|
66
60
|
const fullMessage = `${requireStatement.message ? baseMessageWithRequireMessage : baseMessage}.\nFailing statement: ${statement}`;
|
package/dist/LibauthTemplate.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
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, SignatureAlgorithm, HashType, isUnlockableUtxo, } from './interfaces.js';
|
|
4
|
+
import { isUtxoP2PKH, SignatureAlgorithm, HashType, isUnlockableUtxo, isStandardUnlockableUtxo, } from './interfaces.js';
|
|
5
5
|
import SignatureTemplate from './SignatureTemplate.js';
|
|
6
6
|
import { addressToLockScript, extendedStringify, zip } from './utils.js';
|
|
7
7
|
import { generateUnlockingScriptParams } from './advanced/LibauthTemplate.js';
|
|
@@ -195,21 +195,6 @@ export const generateTemplateScenarioTransactionOutputLockingBytecode = (csOutpu
|
|
|
195
195
|
return {};
|
|
196
196
|
return binToHex(addressToLockScript(csOutput.to));
|
|
197
197
|
};
|
|
198
|
-
/**
|
|
199
|
-
* Generates source outputs for a BitAuth template scenario
|
|
200
|
-
*
|
|
201
|
-
* @param csTransaction - The CashScript transaction to generate source outputs for
|
|
202
|
-
* @returns An array of BitAuth template scenario outputs with locking scripts and values
|
|
203
|
-
*
|
|
204
|
-
* For each input in the transaction:
|
|
205
|
-
* - Generates appropriate locking bytecode (P2PKH or contract)
|
|
206
|
-
* - Includes the input value in satoshis
|
|
207
|
-
* - Includes any token details if present
|
|
208
|
-
*
|
|
209
|
-
* The slotIndex tracks which input is the contract input vs P2PKH inputs
|
|
210
|
-
* to properly generate the locking scripts.
|
|
211
|
-
*/
|
|
212
|
-
// TODO: This looks like it needs some refactor to work with the new stuff
|
|
213
198
|
const generateTemplateScenarioSourceOutputs = (csTransaction) => {
|
|
214
199
|
const slotIndex = csTransaction.inputs.findIndex((input) => !isUtxoP2PKH(input));
|
|
215
200
|
return csTransaction.inputs.map((input, inputIndex) => {
|
|
@@ -239,7 +224,7 @@ export const generateTemplateScenarioBytecode = (input, inputIndex, p2pkhScriptN
|
|
|
239
224
|
},
|
|
240
225
|
};
|
|
241
226
|
}
|
|
242
|
-
if (isUnlockableUtxo(input)) {
|
|
227
|
+
if (isUnlockableUtxo(input) && isStandardUnlockableUtxo(input)) {
|
|
243
228
|
return generateUnlockingScriptParams(input, p2pkhScriptNameTemplate, inputIndex);
|
|
244
229
|
}
|
|
245
230
|
// 'slot' means that we are currently evaluating this specific input,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { HashType, SignatureAlgorithm, P2PKHUnlocker } from './interfaces.js';
|
|
2
2
|
export default class SignatureTemplate {
|
|
3
3
|
private hashtype;
|
|
4
4
|
private signatureAlgorithm;
|
|
@@ -8,7 +8,7 @@ export default class SignatureTemplate {
|
|
|
8
8
|
getHashType(bchForkId?: boolean): number;
|
|
9
9
|
getSignatureAlgorithm(): SignatureAlgorithm;
|
|
10
10
|
getPublicKey(): Uint8Array;
|
|
11
|
-
unlockP2PKH():
|
|
11
|
+
unlockP2PKH(): P2PKHUnlocker;
|
|
12
12
|
}
|
|
13
13
|
interface Keypair {
|
|
14
14
|
toWIF(): string;
|
package/dist/Transaction.js
CHANGED
|
@@ -10,6 +10,7 @@ import { TransactionBuilder } from './TransactionBuilder.js';
|
|
|
10
10
|
import { buildTemplate, getBitauthUri } from './LibauthTemplate.js';
|
|
11
11
|
import { debugTemplate } from './debugging.js';
|
|
12
12
|
import { FailedTransactionError } from './Errors.js';
|
|
13
|
+
import semver from 'semver';
|
|
13
14
|
export class Transaction {
|
|
14
15
|
constructor(contract, unlocker, abiFunction, encodedFunctionArgs, selector) {
|
|
15
16
|
this.contract = contract;
|
|
@@ -113,13 +114,14 @@ export class Transaction {
|
|
|
113
114
|
}
|
|
114
115
|
// method to debug the transaction with libauth VM, throws upon evaluation error
|
|
115
116
|
async debug() {
|
|
116
|
-
if (!this.contract.artifact.
|
|
117
|
-
console.warn('
|
|
117
|
+
if (!semver.satisfies(this.contract.artifact.compiler.version, '>=0.11.0')) {
|
|
118
|
+
console.warn('For the best debugging experience, please recompile your contract with cashc version 0.11.0 or newer.');
|
|
118
119
|
}
|
|
119
120
|
const template = await this.getLibauthTemplate();
|
|
120
121
|
return debugTemplate(template, [this.contract.artifact]);
|
|
121
122
|
}
|
|
122
123
|
async bitauthUri() {
|
|
124
|
+
console.warn('WARNING: it is unsafe to use this Bitauth URI when using real private keys as they are included in the transaction template');
|
|
123
125
|
const template = await this.getLibauthTemplate();
|
|
124
126
|
return getBitauthUri(template);
|
|
125
127
|
}
|
|
@@ -2,6 +2,8 @@ import { Transaction as LibauthTransaction, WalletTemplate } from '@bitauth/liba
|
|
|
2
2
|
import { Unlocker, Output, TransactionDetails, UnlockableUtxo, Utxo, InputOptions } from './interfaces.js';
|
|
3
3
|
import { NetworkProvider } from './network/index.js';
|
|
4
4
|
import { DebugResults } from './debugging.js';
|
|
5
|
+
import { WcTransactionOptions } from './walletconnect-utils.js';
|
|
6
|
+
import { WcTransactionObject } from './walletconnect-utils.js';
|
|
5
7
|
export interface TransactionBuilderOptions {
|
|
6
8
|
provider: NetworkProvider;
|
|
7
9
|
}
|
|
@@ -23,10 +25,11 @@ export declare class TransactionBuilder {
|
|
|
23
25
|
private checkMaxFee;
|
|
24
26
|
buildLibauthTransaction(): LibauthTransaction;
|
|
25
27
|
build(): string;
|
|
26
|
-
debug():
|
|
28
|
+
debug(): DebugResults;
|
|
27
29
|
bitauthUri(): string;
|
|
28
30
|
getLibauthTemplate(): WalletTemplate;
|
|
29
31
|
send(): Promise<TransactionDetails>;
|
|
30
32
|
send(raw: true): Promise<string>;
|
|
31
33
|
private getTxDetails;
|
|
34
|
+
generateWcTransactionObject(options?: WcTransactionOptions): WcTransactionObject;
|
|
32
35
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { binToHex, decodeTransaction, encodeTransaction, hexToBin, } from '@bitauth/libauth';
|
|
1
|
+
import { binToHex, decodeTransaction, decodeTransactionUnsafe, encodeTransaction, hexToBin, } from '@bitauth/libauth';
|
|
2
2
|
import delay from 'delay';
|
|
3
|
-
import { isUnlockableUtxo, } from './interfaces.js';
|
|
4
|
-
import { cashScriptOutputToLibauthOutput, createOpReturnOutput, validateInput, validateOutput, } from './utils.js';
|
|
3
|
+
import { isUnlockableUtxo, isStandardUnlockableUtxo, } from './interfaces.js';
|
|
4
|
+
import { cashScriptOutputToLibauthOutput, createOpReturnOutput, generateLibauthSourceOutputs, validateInput, validateOutput, } from './utils.js';
|
|
5
5
|
import { FailedTransactionError } from './Errors.js';
|
|
6
6
|
import { getBitauthUri } from './LibauthTemplate.js';
|
|
7
7
|
import { debugLibauthTemplate, getLibauthTemplates } from './advanced/LibauthTemplate.js';
|
|
8
|
+
import { getWcContractInfo } from './walletconnect-utils.js';
|
|
9
|
+
import semver from 'semver';
|
|
8
10
|
const DEFAULT_SEQUENCE = 0xfffffffe;
|
|
9
11
|
export class TransactionBuilder {
|
|
10
12
|
constructor(options) {
|
|
@@ -76,14 +78,7 @@ export class TransactionBuilder {
|
|
|
76
78
|
version: 2,
|
|
77
79
|
};
|
|
78
80
|
// Generate source outputs from inputs (for signing with SIGHASH_UTXOS)
|
|
79
|
-
const sourceOutputs = this.inputs
|
|
80
|
-
const sourceOutput = {
|
|
81
|
-
amount: input.satoshis,
|
|
82
|
-
to: input.unlocker.generateLockingBytecode(),
|
|
83
|
-
token: input.token,
|
|
84
|
-
};
|
|
85
|
-
return cashScriptOutputToLibauthOutput(sourceOutput);
|
|
86
|
-
});
|
|
81
|
+
const sourceOutputs = generateLibauthSourceOutputs(this.inputs);
|
|
87
82
|
const inputScripts = this.inputs.map((input, inputIndex) => (input.unlocker.generateUnlockingBytecode({ transaction, sourceOutputs, inputIndex })));
|
|
88
83
|
inputScripts.forEach((script, i) => {
|
|
89
84
|
transaction.inputs[i].unlockingBytecode = script;
|
|
@@ -94,12 +89,21 @@ export class TransactionBuilder {
|
|
|
94
89
|
const transaction = this.buildLibauthTransaction();
|
|
95
90
|
return binToHex(encodeTransaction(transaction));
|
|
96
91
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
92
|
+
debug() {
|
|
93
|
+
if (this.inputs.some((input) => !isStandardUnlockableUtxo(input))) {
|
|
94
|
+
throw new Error('Cannot debug a transaction with custom unlocker');
|
|
95
|
+
}
|
|
96
|
+
// We can typecast this because we check that all inputs are standard unlockable in the check above
|
|
97
|
+
const contractVersions = this.inputs
|
|
98
|
+
.map((input) => 'contract' in input.unlocker ? input.unlocker.contract.artifact.compiler.version : null)
|
|
99
|
+
.filter((version) => version !== null);
|
|
100
|
+
if (!contractVersions.every((version) => semver.satisfies(version, '>=0.11.0'))) {
|
|
101
|
+
console.warn('For the best debugging experience, please recompile your contract with cashc version 0.11.0 or newer.');
|
|
102
|
+
}
|
|
100
103
|
return debugLibauthTemplate(this.getLibauthTemplate(), this);
|
|
101
104
|
}
|
|
102
105
|
bitauthUri() {
|
|
106
|
+
console.warn('WARNING: it is unsafe to use this Bitauth URI when using real private keys as they are included in the transaction template');
|
|
103
107
|
return getBitauthUri(this.getLibauthTemplate());
|
|
104
108
|
}
|
|
105
109
|
getLibauthTemplate() {
|
|
@@ -107,8 +111,11 @@ export class TransactionBuilder {
|
|
|
107
111
|
}
|
|
108
112
|
async send(raw) {
|
|
109
113
|
const tx = this.build();
|
|
110
|
-
//
|
|
111
|
-
|
|
114
|
+
// If all inputs are standard unlockable, we can debug the transaction locally
|
|
115
|
+
// before sending so any errors are caught early
|
|
116
|
+
if (this.inputs.every((input) => isStandardUnlockableUtxo(input))) {
|
|
117
|
+
this.debug();
|
|
118
|
+
}
|
|
112
119
|
try {
|
|
113
120
|
const txid = await this.provider.sendRawTransaction(tx);
|
|
114
121
|
return raw ? await this.getTxDetails(txid, raw) : await this.getTxDetails(txid);
|
|
@@ -135,5 +142,22 @@ export class TransactionBuilder {
|
|
|
135
142
|
// Should not happen
|
|
136
143
|
throw new Error('Could not retrieve transaction details for over 10 minutes');
|
|
137
144
|
}
|
|
145
|
+
generateWcTransactionObject(options) {
|
|
146
|
+
const inputs = this.inputs;
|
|
147
|
+
if (!inputs.every(input => isStandardUnlockableUtxo(input))) {
|
|
148
|
+
throw new Error('All inputs must be StandardUnlockableUtxos to generate the wcSourceOutputs');
|
|
149
|
+
}
|
|
150
|
+
const encodedTransaction = this.build();
|
|
151
|
+
const transaction = decodeTransactionUnsafe(hexToBin(encodedTransaction));
|
|
152
|
+
const libauthSourceOutputs = generateLibauthSourceOutputs(inputs);
|
|
153
|
+
const sourceOutputs = libauthSourceOutputs.map((sourceOutput, index) => {
|
|
154
|
+
return {
|
|
155
|
+
...sourceOutput,
|
|
156
|
+
...transaction.inputs[index],
|
|
157
|
+
...getWcContractInfo(inputs[index]),
|
|
158
|
+
};
|
|
159
|
+
});
|
|
160
|
+
return { ...options, transaction, sourceOutputs };
|
|
161
|
+
}
|
|
138
162
|
}
|
|
139
163
|
//# sourceMappingURL=TransactionBuilder.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { TransactionBch, WalletTemplate, WalletTemplateScenarioBytecode } from '@bitauth/libauth';
|
|
2
|
-
import { AbiFunction
|
|
2
|
+
import { AbiFunction } from '@cashscript/utils';
|
|
3
3
|
import { EncodedConstructorArgument, EncodedFunctionArgument } from '../Argument.js';
|
|
4
4
|
import { Contract } from '../Contract.js';
|
|
5
5
|
import { DebugResults } from '../debugging.js';
|
|
6
|
-
import {
|
|
6
|
+
import { StandardUnlockableUtxo } from '../interfaces.js';
|
|
7
7
|
import SignatureTemplate from '../SignatureTemplate.js';
|
|
8
8
|
import { Transaction } from '../Transaction.js';
|
|
9
9
|
import { TransactionBuilder } from '../TransactionBuilder.js';
|
|
@@ -22,7 +22,7 @@ export declare const generateTemplateEntitiesP2PKH: (inputIndex: number) => Wall
|
|
|
22
22
|
* https://ide.bitauth.com/authentication-template-v0.schema.json
|
|
23
23
|
*
|
|
24
24
|
*/
|
|
25
|
-
export declare const generateTemplateEntitiesP2SH: (
|
|
25
|
+
export declare const generateTemplateEntitiesP2SH: (contract: Contract, abiFunction: AbiFunction, encodedFunctionArgs: EncodedFunctionArgument[], inputIndex: number) => WalletTemplate["entities"];
|
|
26
26
|
/**
|
|
27
27
|
* Generates template scripts for P2PKH (Pay to Public Key Hash) placeholder scripts.
|
|
28
28
|
*
|
|
@@ -38,8 +38,8 @@ export declare const generateTemplateScriptsP2PKH: (template: SignatureTemplate,
|
|
|
38
38
|
* https://ide.bitauth.com/authentication-template-v0.schema.json
|
|
39
39
|
*
|
|
40
40
|
*/
|
|
41
|
-
export declare const generateTemplateScriptsP2SH: (
|
|
41
|
+
export declare const generateTemplateScriptsP2SH: (contract: Contract, abiFunction: AbiFunction, encodedFunctionArgs: EncodedFunctionArgument[], encodedConstructorArgs: EncodedConstructorArgument[], inputIndex: number) => WalletTemplate["scripts"];
|
|
42
42
|
export declare const generateTemplateScenarios: (contract: Contract, libauthTransaction: TransactionBch, csTransaction: Transaction, abiFunction: AbiFunction, encodedFunctionArgs: EncodedFunctionArgument[], inputIndex: number) => WalletTemplate["scenarios"];
|
|
43
43
|
export declare const getLibauthTemplates: (txn: TransactionBuilder) => WalletTemplate;
|
|
44
44
|
export declare const debugLibauthTemplate: (template: WalletTemplate, transaction: TransactionBuilder) => DebugResults;
|
|
45
|
-
export declare const generateUnlockingScriptParams: (csInput:
|
|
45
|
+
export declare const generateUnlockingScriptParams: (csInput: StandardUnlockableUtxo, p2pkhScriptNameTemplate: string, inputIndex: number) => WalletTemplateScenarioBytecode;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { binToHex, } from '@bitauth/libauth';
|
|
1
|
+
import { binToHex, decodeCashAddress, } from '@bitauth/libauth';
|
|
2
2
|
import { encodeFunctionArguments } from '../Argument.js';
|
|
3
3
|
import { debugTemplate } from '../debugging.js';
|
|
4
|
+
import { isP2PKHUnlocker, isStandardUnlockableUtxo, } from '../interfaces.js';
|
|
4
5
|
import { addHexPrefixExceptEmpty, formatBytecodeForDebugging, formatParametersForDebugging, generateTemplateScenarioBytecode, generateTemplateScenarioKeys, generateTemplateScenarioParametersFunctionIndex, generateTemplateScenarioParametersValues, generateTemplateScenarioTransactionOutputLockingBytecode, getHashTypeName, getSignatureAlgorithmName, serialiseTokenDetails, } from '../LibauthTemplate.js';
|
|
5
6
|
import SignatureTemplate from '../SignatureTemplate.js';
|
|
6
7
|
import { addressToLockScript } from '../utils.js';
|
|
@@ -36,21 +37,21 @@ export const generateTemplateEntitiesP2PKH = (inputIndex) => {
|
|
|
36
37
|
* https://ide.bitauth.com/authentication-template-v0.schema.json
|
|
37
38
|
*
|
|
38
39
|
*/
|
|
39
|
-
export const generateTemplateEntitiesP2SH = (
|
|
40
|
+
export const generateTemplateEntitiesP2SH = (contract, abiFunction, encodedFunctionArgs, inputIndex) => {
|
|
40
41
|
const entities = {
|
|
41
|
-
[artifact.contractName + '_input' + inputIndex + '_parameters']: {
|
|
42
|
+
[contract.artifact.contractName + '_input' + inputIndex + '_parameters']: {
|
|
42
43
|
description: 'Contract creation and function parameters',
|
|
43
|
-
name: `${artifact.contractName} (input #${inputIndex})`,
|
|
44
|
+
name: `${contract.artifact.contractName} (input #${inputIndex})`,
|
|
44
45
|
scripts: [
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
getLockScriptName(contract),
|
|
47
|
+
getUnlockScriptName(contract, abiFunction, inputIndex),
|
|
47
48
|
],
|
|
48
|
-
variables: createWalletTemplateVariables(artifact, abiFunction, encodedFunctionArgs),
|
|
49
|
+
variables: createWalletTemplateVariables(contract.artifact, abiFunction, encodedFunctionArgs),
|
|
49
50
|
},
|
|
50
51
|
};
|
|
51
52
|
// function_index is a special variable that indicates the function to execute
|
|
52
|
-
if (artifact.abi.length > 1) {
|
|
53
|
-
entities[artifact.contractName + '_input' + inputIndex + '_parameters'].variables.function_index = {
|
|
53
|
+
if (contract.artifact.abi.length > 1) {
|
|
54
|
+
entities[contract.artifact.contractName + '_input' + inputIndex + '_parameters'].variables.function_index = {
|
|
54
55
|
description: 'Script function index to execute',
|
|
55
56
|
name: 'function_index',
|
|
56
57
|
type: 'WalletData',
|
|
@@ -113,13 +114,13 @@ export const generateTemplateScriptsP2PKH = (template, inputIndex) => {
|
|
|
113
114
|
* https://ide.bitauth.com/authentication-template-v0.schema.json
|
|
114
115
|
*
|
|
115
116
|
*/
|
|
116
|
-
export const generateTemplateScriptsP2SH = (
|
|
117
|
+
export const generateTemplateScriptsP2SH = (contract, abiFunction, encodedFunctionArgs, encodedConstructorArgs, inputIndex) => {
|
|
117
118
|
// definition of locking scripts and unlocking scripts with their respective bytecode
|
|
118
|
-
const unlockingScriptName =
|
|
119
|
-
const lockingScriptName =
|
|
119
|
+
const unlockingScriptName = getUnlockScriptName(contract, abiFunction, inputIndex);
|
|
120
|
+
const lockingScriptName = getLockScriptName(contract);
|
|
120
121
|
return {
|
|
121
|
-
[unlockingScriptName]: generateTemplateUnlockScript(
|
|
122
|
-
[lockingScriptName]: generateTemplateLockScript(
|
|
122
|
+
[unlockingScriptName]: generateTemplateUnlockScript(contract, abiFunction, encodedFunctionArgs, inputIndex),
|
|
123
|
+
[lockingScriptName]: generateTemplateLockScript(contract, encodedConstructorArgs),
|
|
123
124
|
};
|
|
124
125
|
};
|
|
125
126
|
/**
|
|
@@ -129,16 +130,16 @@ export const generateTemplateScriptsP2SH = (artifact, addressType, abiFunction,
|
|
|
129
130
|
* https://ide.bitauth.com/authentication-template-v0.schema.json
|
|
130
131
|
*
|
|
131
132
|
*/
|
|
132
|
-
const generateTemplateLockScript = (
|
|
133
|
+
const generateTemplateLockScript = (contract, constructorArguments) => {
|
|
133
134
|
return {
|
|
134
|
-
lockingType: addressType,
|
|
135
|
-
name: artifact.contractName,
|
|
135
|
+
lockingType: contract.addressType,
|
|
136
|
+
name: contract.artifact.contractName,
|
|
136
137
|
script: [
|
|
137
|
-
`// "${artifact.contractName}" contract constructor parameters`,
|
|
138
|
-
formatParametersForDebugging(artifact.constructorInputs, constructorArguments),
|
|
138
|
+
`// "${contract.artifact.contractName}" contract constructor parameters`,
|
|
139
|
+
formatParametersForDebugging(contract.artifact.constructorInputs, constructorArguments),
|
|
139
140
|
'',
|
|
140
141
|
'// bytecode',
|
|
141
|
-
formatBytecodeForDebugging(artifact),
|
|
142
|
+
formatBytecodeForDebugging(contract.artifact),
|
|
142
143
|
].join('\n'),
|
|
143
144
|
};
|
|
144
145
|
};
|
|
@@ -149,10 +150,10 @@ const generateTemplateLockScript = (artifact, addressType, constructorArguments)
|
|
|
149
150
|
* https://ide.bitauth.com/authentication-template-v0.schema.json
|
|
150
151
|
*
|
|
151
152
|
*/
|
|
152
|
-
const generateTemplateUnlockScript = (
|
|
153
|
-
const scenarioIdentifier = `${artifact.contractName}_${abiFunction.name}_input${inputIndex}_evaluate`;
|
|
154
|
-
const functionIndex = artifact.abi.findIndex((func) => func.name === abiFunction.name);
|
|
155
|
-
const functionIndexString = artifact.abi.length > 1
|
|
153
|
+
const generateTemplateUnlockScript = (contract, abiFunction, encodedFunctionArgs, inputIndex) => {
|
|
154
|
+
const scenarioIdentifier = `${contract.artifact.contractName}_${abiFunction.name}_input${inputIndex}_evaluate`;
|
|
155
|
+
const functionIndex = contract.artifact.abi.findIndex((func) => func.name === abiFunction.name);
|
|
156
|
+
const functionIndexString = contract.artifact.abi.length > 1
|
|
156
157
|
? ['// function index in contract', `<function_index> // int = <${functionIndex}>`, '']
|
|
157
158
|
: [];
|
|
158
159
|
return {
|
|
@@ -165,7 +166,7 @@ const generateTemplateUnlockScript = (artifact, abiFunction, encodedFunctionArgs
|
|
|
165
166
|
'',
|
|
166
167
|
...functionIndexString,
|
|
167
168
|
].join('\n'),
|
|
168
|
-
unlocks:
|
|
169
|
+
unlocks: getLockScriptName(contract),
|
|
169
170
|
};
|
|
170
171
|
};
|
|
171
172
|
export const generateTemplateScenarios = (contract, libauthTransaction, csTransaction, abiFunction, encodedFunctionArgs, inputIndex) => {
|
|
@@ -247,6 +248,9 @@ const createCSTransaction = (txn) => {
|
|
|
247
248
|
return csTransaction;
|
|
248
249
|
};
|
|
249
250
|
export const getLibauthTemplates = (txn) => {
|
|
251
|
+
if (txn.inputs.some((input) => !isStandardUnlockableUtxo(input))) {
|
|
252
|
+
throw new Error('Cannot use debugging functionality with a transaction that contains custom unlockers');
|
|
253
|
+
}
|
|
250
254
|
const libauthTransaction = txn.buildLibauthTransaction();
|
|
251
255
|
const csTransaction = createCSTransaction(txn);
|
|
252
256
|
const baseTemplate = {
|
|
@@ -269,10 +273,11 @@ export const getLibauthTemplates = (txn) => {
|
|
|
269
273
|
// Initialize bytecode mappings, these will be used to map the locking and unlocking scripts and naming the scripts
|
|
270
274
|
const unlockingBytecodeToLockingBytecodeParams = {};
|
|
271
275
|
const lockingBytecodeToLockingBytecodeParams = {};
|
|
276
|
+
// We can typecast this because we check that all inputs are standard unlockable at the top of this function
|
|
272
277
|
for (const [inputIndex, input] of txn.inputs.entries()) {
|
|
273
278
|
// If template exists on the input, it indicates this is a P2PKH (Pay to Public Key Hash) input
|
|
274
279
|
if ('template' in input.unlocker) {
|
|
275
|
-
// @ts-ignore TODO: Remove UtxoP2PKH type and only use UnlockableUtxo in
|
|
280
|
+
// @ts-ignore TODO: Remove UtxoP2PKH type and only use UnlockableUtxo in Libauth Template generation
|
|
276
281
|
input.template = input.unlocker?.template; // Added to support P2PKH inputs in buildTemplate
|
|
277
282
|
Object.assign(p2pkhEntities, generateTemplateEntitiesP2PKH(inputIndex));
|
|
278
283
|
Object.assign(p2pkhScripts, generateTemplateScriptsP2PKH(input.unlocker.template, inputIndex));
|
|
@@ -290,9 +295,9 @@ export const getLibauthTemplates = (txn) => {
|
|
|
290
295
|
// Generate a scenario object for this contract input
|
|
291
296
|
Object.assign(scenarios, generateTemplateScenarios(contract, libauthTransaction, csTransaction, abiFunction, encodedArgs, inputIndex));
|
|
292
297
|
// Generate entities for this contract input
|
|
293
|
-
const entity = generateTemplateEntitiesP2SH(contract
|
|
298
|
+
const entity = generateTemplateEntitiesP2SH(contract, abiFunction, encodedArgs, inputIndex);
|
|
294
299
|
// Generate scripts for this contract input
|
|
295
|
-
const script = generateTemplateScriptsP2SH(contract
|
|
300
|
+
const script = generateTemplateScriptsP2SH(contract, abiFunction, encodedArgs, contract.encodedConstructorArgs, inputIndex);
|
|
296
301
|
// Find the lock script name for this contract input
|
|
297
302
|
const lockScriptName = Object.keys(script).find(scriptName => scriptName.includes('_lock'));
|
|
298
303
|
if (lockScriptName) {
|
|
@@ -359,8 +364,8 @@ export const debugLibauthTemplate = (template, transaction) => {
|
|
|
359
364
|
.map(contract => contract.artifact);
|
|
360
365
|
return debugTemplate(template, allArtifacts);
|
|
361
366
|
};
|
|
362
|
-
const generateLockingScriptParams = (contract,
|
|
363
|
-
if ((
|
|
367
|
+
const generateLockingScriptParams = (contract, { unlocker }, lockScriptName) => {
|
|
368
|
+
if (isP2PKHUnlocker(unlocker)) {
|
|
364
369
|
return {
|
|
365
370
|
script: lockScriptName,
|
|
366
371
|
};
|
|
@@ -368,8 +373,7 @@ const generateLockingScriptParams = (contract, csInput, lockScriptName) => {
|
|
|
368
373
|
const constructorParamsEntries = contract.artifact.constructorInputs
|
|
369
374
|
.map(({ name }, index) => [
|
|
370
375
|
name,
|
|
371
|
-
|
|
372
|
-
addHexPrefixExceptEmpty(binToHex(csInput.unlocker.contract.encodedConstructorArgs[index])),
|
|
376
|
+
addHexPrefixExceptEmpty(binToHex(unlocker.contract.encodedConstructorArgs[index])),
|
|
373
377
|
]);
|
|
374
378
|
const constructorParams = Object.fromEntries(constructorParamsEntries);
|
|
375
379
|
return {
|
|
@@ -380,7 +384,7 @@ const generateLockingScriptParams = (contract, csInput, lockScriptName) => {
|
|
|
380
384
|
};
|
|
381
385
|
};
|
|
382
386
|
export const generateUnlockingScriptParams = (csInput, p2pkhScriptNameTemplate, inputIndex) => {
|
|
383
|
-
if ((
|
|
387
|
+
if (isP2PKHUnlocker(csInput.unlocker)) {
|
|
384
388
|
return {
|
|
385
389
|
script: `${p2pkhScriptNameTemplate}_${inputIndex}`,
|
|
386
390
|
overrides: {
|
|
@@ -396,7 +400,7 @@ export const generateUnlockingScriptParams = (csInput, p2pkhScriptNameTemplate,
|
|
|
396
400
|
const contract = csInput.unlocker.contract;
|
|
397
401
|
const encodedFunctionArgs = encodeFunctionArguments(abiFunction, csInput.unlocker.params);
|
|
398
402
|
return {
|
|
399
|
-
script:
|
|
403
|
+
script: getUnlockScriptName(contract, abiFunction, inputIndex),
|
|
400
404
|
overrides: {
|
|
401
405
|
// encode values for the variables defined above in `entities` property
|
|
402
406
|
bytecode: {
|
|
@@ -410,4 +414,13 @@ export const generateUnlockingScriptParams = (csInput, p2pkhScriptNameTemplate,
|
|
|
410
414
|
},
|
|
411
415
|
};
|
|
412
416
|
};
|
|
417
|
+
const getLockScriptName = (contract) => {
|
|
418
|
+
const result = decodeCashAddress(contract.address);
|
|
419
|
+
if (typeof result === 'string')
|
|
420
|
+
throw new Error(result);
|
|
421
|
+
return `${contract.artifact.contractName}_${binToHex(result.payload)}_lock`;
|
|
422
|
+
};
|
|
423
|
+
const getUnlockScriptName = (contract, abiFunction, inputIndex) => {
|
|
424
|
+
return `${contract.artifact.contractName}_${abiFunction.name}_input${inputIndex}_unlock`;
|
|
425
|
+
};
|
|
413
426
|
//# sourceMappingURL=LibauthTemplate.js.map
|
package/dist/debugging.js
CHANGED
|
@@ -5,6 +5,11 @@ import { FailedRequireError, FailedTransactionError, FailedTransactionEvaluation
|
|
|
5
5
|
import { getBitauthUri } from './LibauthTemplate.js';
|
|
6
6
|
// debugs the template, optionally logging the execution data
|
|
7
7
|
export const debugTemplate = (template, artifacts) => {
|
|
8
|
+
// If a contract has the same name, but a different bytecode, then it is considered a name collision
|
|
9
|
+
const hasArtifactNameCollision = artifacts.some((artifact) => (artifacts.some((other) => other.contractName === artifact.contractName && other.bytecode !== artifact.bytecode)));
|
|
10
|
+
if (hasArtifactNameCollision) {
|
|
11
|
+
throw new Error('There are multiple artifacts with the same contractName. Please make sure that all artifacts have unique names.');
|
|
12
|
+
}
|
|
8
13
|
const results = {};
|
|
9
14
|
const unlockingScriptIds = Object.keys(template.scripts).filter((key) => 'unlocks' in template.scripts[key]);
|
|
10
15
|
for (const unlockingScriptId of unlockingScriptIds) {
|
|
@@ -173,7 +178,10 @@ const calculateCleanupSize = (instructions) => {
|
|
|
173
178
|
// OP_NIP (or OP_DROP/OP_2DROP in optimised bytecode) is used for cleanup at the end of a function,
|
|
174
179
|
// OP_ENDIF and OP_ELSE are the end of branches. We need to remove all of these to get to the actual last
|
|
175
180
|
// executed instruction of a function
|
|
176
|
-
//
|
|
181
|
+
// Note that in the case where we re-add OP_1 because we cannot optimise the final explicit VERIFY into an implicit one
|
|
182
|
+
// (like when dealing with if-statements, or with CHECKLOCKTIMEVERIFY), it is impossible to run into an implicit final
|
|
183
|
+
// verify failure. That is why OP_1 does not need to be included in the cleanup opcodes.
|
|
184
|
+
// TODO: Perhaps we also do not need to add OP_DROP/OP_2DROP either, because they only occur together with OP_1
|
|
177
185
|
const cleanupOpcodes = [Op.OP_ENDIF, Op.OP_NIP, Op.OP_ELSE, Op.OP_DROP, Op.OP_2DROP];
|
|
178
186
|
let cleanupSize = 0;
|
|
179
187
|
for (const instruction of [...instructions].reverse()) {
|
package/dist/index.d.ts
CHANGED
|
@@ -9,3 +9,4 @@ export * from './interfaces.js';
|
|
|
9
9
|
export * from './Errors.js';
|
|
10
10
|
export { type NetworkProvider, BitcoinRpcNetworkProvider, ElectrumNetworkProvider, FullStackNetworkProvider, MockNetworkProvider, } from './network/index.js';
|
|
11
11
|
export { randomUtxo, randomToken, randomNFT } from './utils.js';
|
|
12
|
+
export * from './walletconnect-utils.js';
|
package/dist/index.js
CHANGED
|
@@ -8,4 +8,5 @@ export * from './interfaces.js';
|
|
|
8
8
|
export * from './Errors.js';
|
|
9
9
|
export { BitcoinRpcNetworkProvider, ElectrumNetworkProvider, FullStackNetworkProvider, MockNetworkProvider, } from './network/index.js';
|
|
10
10
|
export { randomUtxo, randomToken, randomNFT } from './utils.js';
|
|
11
|
+
export * from './walletconnect-utils.js';
|
|
11
12
|
//# sourceMappingURL=index.js.map
|
package/dist/interfaces.d.ts
CHANGED
|
@@ -14,7 +14,11 @@ export interface UnlockableUtxo extends Utxo {
|
|
|
14
14
|
unlocker: Unlocker;
|
|
15
15
|
options?: InputOptions;
|
|
16
16
|
}
|
|
17
|
+
export interface StandardUnlockableUtxo extends UnlockableUtxo {
|
|
18
|
+
unlocker: StandardUnlocker;
|
|
19
|
+
}
|
|
17
20
|
export declare function isUnlockableUtxo(utxo: Utxo): utxo is UnlockableUtxo;
|
|
21
|
+
export declare function isStandardUnlockableUtxo(utxo: UnlockableUtxo): utxo is StandardUnlockableUtxo;
|
|
18
22
|
export interface InputOptions {
|
|
19
23
|
sequence?: number;
|
|
20
24
|
}
|
|
@@ -23,19 +27,22 @@ export interface GenerateUnlockingBytecodeOptions {
|
|
|
23
27
|
sourceOutputs: LibauthOutput[];
|
|
24
28
|
inputIndex: number;
|
|
25
29
|
}
|
|
26
|
-
export interface
|
|
30
|
+
export interface Unlocker {
|
|
27
31
|
generateLockingBytecode: () => Uint8Array;
|
|
28
32
|
generateUnlockingBytecode: (options: GenerateUnlockingBytecodeOptions) => Uint8Array;
|
|
29
33
|
}
|
|
30
|
-
export interface ContractUnlocker extends
|
|
34
|
+
export interface ContractUnlocker extends Unlocker {
|
|
31
35
|
contract: Contract;
|
|
32
36
|
params: FunctionArgument[];
|
|
33
37
|
abiFunction: AbiFunction;
|
|
34
38
|
}
|
|
35
|
-
export interface P2PKHUnlocker extends
|
|
39
|
+
export interface P2PKHUnlocker extends Unlocker {
|
|
36
40
|
template: SignatureTemplate;
|
|
37
41
|
}
|
|
38
|
-
export type
|
|
42
|
+
export type StandardUnlocker = ContractUnlocker | P2PKHUnlocker;
|
|
43
|
+
export declare function isContractUnlocker(unlocker: Unlocker): unlocker is ContractUnlocker;
|
|
44
|
+
export declare function isP2PKHUnlocker(unlocker: Unlocker): unlocker is P2PKHUnlocker;
|
|
45
|
+
export declare function isStandardUnlocker(unlocker: Unlocker): unlocker is StandardUnlocker;
|
|
39
46
|
export interface UtxoP2PKH extends Utxo {
|
|
40
47
|
template: SignatureTemplate;
|
|
41
48
|
}
|
package/dist/interfaces.js
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
export function isUnlockableUtxo(utxo) {
|
|
2
2
|
return 'unlocker' in utxo;
|
|
3
3
|
}
|
|
4
|
+
export function isStandardUnlockableUtxo(utxo) {
|
|
5
|
+
return isStandardUnlocker(utxo.unlocker);
|
|
6
|
+
}
|
|
7
|
+
export function isContractUnlocker(unlocker) {
|
|
8
|
+
return 'contract' in unlocker;
|
|
9
|
+
}
|
|
10
|
+
export function isP2PKHUnlocker(unlocker) {
|
|
11
|
+
return 'template' in unlocker;
|
|
12
|
+
}
|
|
13
|
+
export function isStandardUnlocker(unlocker) {
|
|
14
|
+
return isContractUnlocker(unlocker) || isP2PKHUnlocker(unlocker);
|
|
15
|
+
}
|
|
4
16
|
export function isUtxoP2PKH(utxo) {
|
|
5
17
|
return 'template' in utxo;
|
|
6
18
|
}
|
|
@@ -4,8 +4,10 @@ export default class MockNetworkProvider implements NetworkProvider {
|
|
|
4
4
|
private utxoMap;
|
|
5
5
|
private transactionMap;
|
|
6
6
|
network: Network;
|
|
7
|
+
blockHeight: number;
|
|
7
8
|
constructor();
|
|
8
9
|
getUtxos(address: string): Promise<Utxo[]>;
|
|
10
|
+
setBlockHeight(newBlockHeight: number): void;
|
|
9
11
|
getBlockHeight(): Promise<number>;
|
|
10
12
|
getRawTransaction(txid: string): Promise<string>;
|
|
11
13
|
sendRawTransaction(txHex: string): Promise<string>;
|
|
@@ -11,6 +11,7 @@ export default class MockNetworkProvider {
|
|
|
11
11
|
this.utxoMap = {};
|
|
12
12
|
this.transactionMap = {};
|
|
13
13
|
this.network = Network.MOCKNET;
|
|
14
|
+
this.blockHeight = 133700;
|
|
14
15
|
for (let i = 0; i < 3; i += 1) {
|
|
15
16
|
this.addUtxo(aliceAddress, randomUtxo());
|
|
16
17
|
this.addUtxo(bobAddress, randomUtxo());
|
|
@@ -21,8 +22,11 @@ export default class MockNetworkProvider {
|
|
|
21
22
|
const lockingBytecode = binToHex(addressToLockScript(address));
|
|
22
23
|
return this.utxoMap[lockingBytecode] ?? [];
|
|
23
24
|
}
|
|
25
|
+
setBlockHeight(newBlockHeight) {
|
|
26
|
+
this.blockHeight = newBlockHeight;
|
|
27
|
+
}
|
|
24
28
|
async getBlockHeight() {
|
|
25
|
-
return
|
|
29
|
+
return this.blockHeight;
|
|
26
30
|
}
|
|
27
31
|
async getRawTransaction(txid) {
|
|
28
32
|
return this.transactionMap[txid];
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
expect.extend({
|
|
2
|
-
|
|
2
|
+
toLog(transaction, match) {
|
|
3
3
|
const loggerSpy = jest.spyOn(console, 'log');
|
|
4
4
|
// Clear any previous calls (if spy reused accidentally)
|
|
5
5
|
loggerSpy.mockClear();
|
|
6
6
|
// silence actual stdout output
|
|
7
7
|
loggerSpy.mockImplementation(() => { });
|
|
8
8
|
try {
|
|
9
|
-
|
|
9
|
+
executeDebug(transaction);
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
if (error instanceof OldTransactionBuilderError)
|
|
13
|
+
throw error;
|
|
10
14
|
}
|
|
11
|
-
catch { }
|
|
12
15
|
// We concatenate all the logs into a single string - if no logs are present, we set received to undefined
|
|
13
16
|
const receivedBase = loggerSpy.mock.calls.reduce((acc, [log]) => `${acc}\n${log}`, '').trim();
|
|
14
17
|
const received = receivedBase === '' ? undefined : receivedBase;
|
|
@@ -17,25 +20,37 @@ expect.extend({
|
|
|
17
20
|
const receivedText = `Received: ${this.utils.printReceived(received)}`;
|
|
18
21
|
const message = () => `${matcherHint}\n\n${expectedText}\n${receivedText}`;
|
|
19
22
|
try {
|
|
20
|
-
|
|
23
|
+
// We first check if the expected string is present in any of the individual console.log calls
|
|
24
|
+
expect(loggerSpy).toHaveBeenCalledWith(match ? expect.stringMatching(match) : expect.anything());
|
|
21
25
|
}
|
|
22
|
-
catch
|
|
23
|
-
|
|
26
|
+
catch {
|
|
27
|
+
try {
|
|
28
|
+
// We add this extra check to allow expect().toLog() to check multiple console.log calls in a single test
|
|
29
|
+
// (e.g. for log ordering), which would fail the first check because that compares the individual console.log calls
|
|
30
|
+
expect(receivedBase).toMatch(match ? match : expect.anything());
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return { message, pass: false };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
// Restore the original console.log implementation
|
|
38
|
+
loggerSpy.mockRestore();
|
|
24
39
|
}
|
|
25
|
-
// Restore the original console.log implementation
|
|
26
|
-
loggerSpy.mockRestore();
|
|
27
40
|
return { message, pass: true };
|
|
28
41
|
},
|
|
29
42
|
});
|
|
30
43
|
expect.extend({
|
|
31
|
-
|
|
44
|
+
toFailRequireWith(transaction, match) {
|
|
32
45
|
try {
|
|
33
|
-
|
|
46
|
+
executeDebug(transaction);
|
|
34
47
|
const matcherHint = this.utils.matcherHint('.toFailRequireWith', undefined, match.toString(), { isNot: this.isNot });
|
|
35
48
|
const message = () => `${matcherHint}\n\nContract function did not fail a require statement.`;
|
|
36
49
|
return { message, pass: false };
|
|
37
50
|
}
|
|
38
51
|
catch (transactionError) {
|
|
52
|
+
if (transactionError instanceof OldTransactionBuilderError)
|
|
53
|
+
throw transactionError;
|
|
39
54
|
const matcherHint = this.utils.matcherHint('toFailRequireWith', 'received', 'expected', { isNot: this.isNot });
|
|
40
55
|
const expectedText = `Expected pattern: ${this.isNot ? 'not ' : ''}${this.utils.printExpected(match)}`;
|
|
41
56
|
const receivedText = `Received string: ${this.utils.printReceived(transactionError?.message ?? '')}`;
|
|
@@ -49,18 +64,35 @@ expect.extend({
|
|
|
49
64
|
}
|
|
50
65
|
}
|
|
51
66
|
},
|
|
52
|
-
|
|
67
|
+
toFailRequire(transaction) {
|
|
53
68
|
try {
|
|
54
|
-
|
|
69
|
+
executeDebug(transaction);
|
|
55
70
|
const message = () => 'Contract function did not fail a require statement.';
|
|
56
71
|
return { message, pass: false };
|
|
57
72
|
}
|
|
58
73
|
catch (transactionError) {
|
|
74
|
+
if (transactionError instanceof OldTransactionBuilderError)
|
|
75
|
+
throw transactionError;
|
|
59
76
|
const receivedText = `Received string: ${this.utils.printReceived(transactionError?.message ?? '')}`;
|
|
60
77
|
const message = () => `Contract function failed a require statement.\n${receivedText}`;
|
|
61
78
|
return { message, pass: true };
|
|
62
79
|
}
|
|
63
80
|
},
|
|
64
81
|
});
|
|
82
|
+
// Wrapper function with custom error in case people use it with the old transaction builder
|
|
83
|
+
// This is a temporary solution until we fully remove the old transaction builder from the SDK
|
|
84
|
+
const executeDebug = (transaction) => {
|
|
85
|
+
const debugResults = transaction.debug();
|
|
86
|
+
if (debugResults instanceof Promise) {
|
|
87
|
+
debugResults.catch(() => { });
|
|
88
|
+
throw new OldTransactionBuilderError();
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
class OldTransactionBuilderError extends Error {
|
|
92
|
+
constructor() {
|
|
93
|
+
super('The CashScript JestExtensions do not support the old transaction builder since v0.11.0. Please use the new TransactionBuilder class.');
|
|
94
|
+
this.name = 'OldTransactionBuilderError';
|
|
95
|
+
}
|
|
96
|
+
}
|
|
65
97
|
export {};
|
|
66
98
|
//# sourceMappingURL=JestExtensions.js.map
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Transaction } from '@bitauth/libauth';
|
|
2
2
|
import { Script } from '@cashscript/utils';
|
|
3
|
-
import { Utxo, Output, LibauthOutput, TokenDetails, AddressType } from './interfaces.js';
|
|
3
|
+
import { Utxo, Output, LibauthOutput, TokenDetails, AddressType, UnlockableUtxo } from './interfaces.js';
|
|
4
4
|
export declare function validateInput(utxo: Utxo): void;
|
|
5
5
|
export declare function validateOutput(output: Output): void;
|
|
6
6
|
export declare function calculateDust(output: Output): number;
|
|
@@ -8,6 +8,7 @@ export declare function getOutputSize(output: Output): number;
|
|
|
8
8
|
export declare function encodeOutput(output: Output): Uint8Array;
|
|
9
9
|
export declare function cashScriptOutputToLibauthOutput(output: Output): LibauthOutput;
|
|
10
10
|
export declare function libauthOutputToCashScriptOutput(output: LibauthOutput): Output;
|
|
11
|
+
export declare function generateLibauthSourceOutputs(inputs: UnlockableUtxo[]): LibauthOutput[];
|
|
11
12
|
export declare function getInputSize(inputScript: Uint8Array): number;
|
|
12
13
|
export declare function getTxSizeWithoutInputs(outputs: Output[]): number;
|
|
13
14
|
export declare function createInputScript(redeemScript: Script, encodedArgs: Uint8Array[], selector?: number): Uint8Array;
|
package/dist/utils.js
CHANGED
|
@@ -74,6 +74,17 @@ export function libauthOutputToCashScriptOutput(output) {
|
|
|
74
74
|
},
|
|
75
75
|
};
|
|
76
76
|
}
|
|
77
|
+
export function generateLibauthSourceOutputs(inputs) {
|
|
78
|
+
const sourceOutputs = inputs.map((input) => {
|
|
79
|
+
const sourceOutput = {
|
|
80
|
+
amount: input.satoshis,
|
|
81
|
+
to: input.unlocker.generateLockingBytecode(),
|
|
82
|
+
token: input.token,
|
|
83
|
+
};
|
|
84
|
+
return cashScriptOutputToLibauthOutput(sourceOutput);
|
|
85
|
+
});
|
|
86
|
+
return sourceOutputs;
|
|
87
|
+
}
|
|
77
88
|
function isTokenAddress(address) {
|
|
78
89
|
const result = decodeCashAddress(address);
|
|
79
90
|
if (typeof result === 'string')
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { StandardUnlockableUtxo, LibauthOutput, Unlocker } from './interfaces.js';
|
|
2
|
+
import { type AbiFunction, type Artifact } from '@cashscript/utils';
|
|
3
|
+
import { type Input, type TransactionCommon } from '@bitauth/libauth';
|
|
4
|
+
export interface WcTransactionOptions {
|
|
5
|
+
broadcast?: boolean;
|
|
6
|
+
userPrompt?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface WcTransactionObject {
|
|
9
|
+
transaction: TransactionCommon | string;
|
|
10
|
+
sourceOutputs: WcSourceOutput[];
|
|
11
|
+
broadcast?: boolean;
|
|
12
|
+
userPrompt?: string;
|
|
13
|
+
}
|
|
14
|
+
export type WcSourceOutput = Input & LibauthOutput & WcContractInfo;
|
|
15
|
+
export interface WcContractInfo {
|
|
16
|
+
contract?: {
|
|
17
|
+
abiFunction: AbiFunction;
|
|
18
|
+
redeemScript: Uint8Array;
|
|
19
|
+
artifact: Partial<Artifact>;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export declare function getWcContractInfo(input: StandardUnlockableUtxo): WcContractInfo | {};
|
|
23
|
+
export declare const placeholderSignature: () => Uint8Array;
|
|
24
|
+
export declare const placeholderPublicKey: () => Uint8Array;
|
|
25
|
+
export declare const placeholderP2PKHUnlocker: (userAddress: string) => Unlocker;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { scriptToBytecode } from '@cashscript/utils';
|
|
2
|
+
import { cashAddressToLockingBytecode } from '@bitauth/libauth';
|
|
3
|
+
export function getWcContractInfo(input) {
|
|
4
|
+
// If the input does not have a contract unlocker, return an empty object
|
|
5
|
+
if (!('contract' in input.unlocker))
|
|
6
|
+
return {};
|
|
7
|
+
const contract = input.unlocker.contract;
|
|
8
|
+
const abiFunctionName = input.unlocker.abiFunction?.name;
|
|
9
|
+
const abiFunction = contract.artifact.abi.find(abi => abi.name === abiFunctionName);
|
|
10
|
+
if (!abiFunction) {
|
|
11
|
+
throw new Error(`ABI function ${abiFunctionName} not found in contract artifact`);
|
|
12
|
+
}
|
|
13
|
+
const wcContractObj = {
|
|
14
|
+
contract: {
|
|
15
|
+
abiFunction: abiFunction,
|
|
16
|
+
redeemScript: scriptToBytecode(contract.redeemScript),
|
|
17
|
+
artifact: contract.artifact,
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
return wcContractObj;
|
|
21
|
+
}
|
|
22
|
+
export const placeholderSignature = () => Uint8Array.from(Array(65));
|
|
23
|
+
export const placeholderPublicKey = () => Uint8Array.from(Array(33));
|
|
24
|
+
export const placeholderP2PKHUnlocker = (userAddress) => {
|
|
25
|
+
const decodeAddressResult = cashAddressToLockingBytecode(userAddress);
|
|
26
|
+
if (typeof decodeAddressResult === 'string') {
|
|
27
|
+
throw new Error(`Invalid address: ${decodeAddressResult}`);
|
|
28
|
+
}
|
|
29
|
+
const lockingBytecode = decodeAddressResult.bytecode;
|
|
30
|
+
return {
|
|
31
|
+
generateLockingBytecode: () => lockingBytecode,
|
|
32
|
+
generateUnlockingBytecode: () => Uint8Array.from(Array(0)),
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=walletconnect-utils.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cashscript",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "Easily write and interact with Bitcoin Cash contracts",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bitcoin cash",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@bitauth/libauth": "^3.1.0-next.2",
|
|
49
|
-
"@cashscript/utils": "^0.11.
|
|
49
|
+
"@cashscript/utils": "^0.11.1",
|
|
50
50
|
"@electrum-cash/network": "^4.1.1",
|
|
51
51
|
"@mr-zwets/bchn-api-wrapper": "^1.0.1",
|
|
52
52
|
"delay": "^6.0.0",
|
|
@@ -63,5 +63,5 @@
|
|
|
63
63
|
"jest": "^29.7.0",
|
|
64
64
|
"typescript": "^5.7.3"
|
|
65
65
|
},
|
|
66
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "ecd880401ed92fa7740ccd23d405f10b2fb61a29"
|
|
67
67
|
}
|