Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

cashscript

Package Overview
Dependencies
Maintainers
1
Versions
64
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cashscript - npm Package Compare versions

Comparing version 0.4.4 to 0.5.0

dist/Argument.d.ts

28

dist/Contract.d.ts
import { Artifact } from 'cashc';
import { Transaction } from './Transaction';
import { Instance } from './Instance';
import { Parameter } from './Parameter';
import { Argument } from './Argument';
import { Utxo } from './interfaces';
import NetworkProvider from './network/NetworkProvider';
export declare class Contract {
artifact: Artifact;
private network;
private artifact;
private provider;
name: string;
new: (...params: Parameter[]) => Instance;
deployed: (at?: string) => Instance;
static compile(fnOrString: string, network?: string): Contract;
static import(fnOrArtifact: string | Artifact, network?: string): Contract;
export(fn?: string): Artifact;
constructor(artifact: Artifact, network?: string);
address: string;
bytesize: number;
opcount: number;
functions: {
[name: string]: ContractFunction;
};
private redeemScript;
constructor(artifact: Artifact, constructorArgs: Argument[], provider?: NetworkProvider);
getBalance(): Promise<number>;
getUtxos(): Promise<Utxo[]>;
private createFunction;
}
export declare type ContractFunction = (...parameters: Parameter[]) => Transaction;
export declare type ContractFunction = (...args: Argument[]) => Transaction;
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {

@@ -7,9 +16,11 @@ return (mod && mod.__esModule) ? mod : { "default": mod };

const cashc_1 = require("cashc");
const fs_1 = __importDefault(require("fs"));
const Instance_1 = require("./Instance");
const Parameter_1 = require("./Parameter");
const Transaction_1 = require("./Transaction");
const Argument_1 = require("./Argument");
const util_1 = require("./util");
const SignatureTemplate_1 = __importDefault(require("./SignatureTemplate"));
const network_1 = require("./network");
class Contract {
constructor(artifact, network = 'testnet') {
constructor(artifact, constructorArgs, provider = new network_1.ElectrumNetworkProvider()) {
this.artifact = artifact;
this.network = network;
this.provider = provider;
if (!artifact.abi || !artifact.bytecode

@@ -19,52 +30,55 @@ || !artifact.constructorInputs || !artifact.contractName) {

}
if (artifact.constructorInputs.length !== constructorArgs.length) {
throw new Error(`Incorrect number of arguments passed to ${artifact.contractName} constructor`);
}
// Encode arguments (this also performs type checking)
const encodedArgs = constructorArgs
.map((arg, i) => Argument_1.encodeArgument(arg, artifact.constructorInputs[i].type))
.reverse();
// Check there's no signature templates in the constructor
if (encodedArgs.some(arg => arg instanceof SignatureTemplate_1.default)) {
throw new Error('Cannot use signatures in constructor');
}
this.redeemScript = [
...encodedArgs,
...cashc_1.Data.asmToScript(this.artifact.bytecode),
];
// Populate the functions object with the contract's functions
// (with a special case for single function, which has no "function selector")
this.functions = {};
if (artifact.abi.length === 1) {
const f = artifact.abi[0];
this.functions[f.name] = this.createFunction(f);
}
else {
artifact.abi.forEach((f, i) => {
this.functions[f.name] = this.createFunction(f, i);
});
}
this.name = artifact.contractName;
this.new = (...ps) => {
if (artifact.constructorInputs.length !== ps.length) {
throw new Error(`Incorrect number of arguments passed to ${artifact.contractName} constructor`);
}
const encodedParameters = ps
.map((p, i) => Parameter_1.encodeParameter(p, artifact.constructorInputs[i].type))
.reverse();
// Check there's no sigs in the constructor
if (encodedParameters.some(p => p instanceof Parameter_1.SignatureTemplate)) {
throw new Error('Cannot use signatures in constructor');
}
const redeemScript = [
...encodedParameters,
...cashc_1.Data.asmToScript(this.artifact.bytecode),
];
const instance = new Instance_1.Instance(this.artifact, redeemScript, this.network);
const deployedContracts = this.artifact.networks[this.network] || {};
deployedContracts[instance.address] = cashc_1.Data.scriptToAsm(redeemScript);
this.artifact.networks[this.network] = deployedContracts;
this.artifact.updatedAt = new Date().toISOString();
return instance;
};
this.deployed = (at) => {
if (!this.artifact.networks[this.network])
throw new Error('No registered deployed contracts');
const redeemScript = at
? this.artifact.networks[this.network][at]
: Object.values(this.artifact.networks[this.network])[0];
if (!redeemScript)
throw new Error(`No registered contract deployed at ${at}`);
return new Instance_1.Instance(this.artifact, cashc_1.Data.asmToScript(redeemScript), this.network);
};
this.address = util_1.scriptToAddress(this.redeemScript, this.provider.network);
this.bytesize = util_1.calculateBytesize(this.redeemScript);
this.opcount = util_1.countOpcodes(this.redeemScript);
}
static compile(fnOrString, network) {
const artifact = fs_1.default && fs_1.default.existsSync && fs_1.default.existsSync(fnOrString)
? cashc_1.CashCompiler.compileFile(fnOrString)
: cashc_1.CashCompiler.compileString(fnOrString);
return new Contract(artifact, network);
getBalance() {
return __awaiter(this, void 0, void 0, function* () {
const utxos = yield this.getUtxos();
return utxos.reduce((acc, utxo) => acc + utxo.satoshis, 0);
});
}
static import(fnOrArtifact, network) {
const artifact = typeof fnOrArtifact === 'string'
? cashc_1.Artifacts.require(fnOrArtifact)
: fnOrArtifact;
return new Contract(artifact, network);
getUtxos() {
return __awaiter(this, void 0, void 0, function* () {
return this.provider.getUtxos(this.address);
});
}
export(fn) {
if (typeof fn !== 'undefined')
cashc_1.Artifacts.export(this.artifact, fn);
return this.artifact;
createFunction(abiFunction, selector) {
return (...args) => {
if (abiFunction.inputs.length !== args.length) {
throw new Error(`Incorrect number of arguments passed to function ${abiFunction.name}`);
}
// Encode passed args (this also performs type checking)
const encodedArgs = args
.map((arg, i) => Argument_1.encodeArgument(arg, abiFunction.inputs[i].type));
return new Transaction_1.Transaction(this.address, this.provider, this.redeemScript, abiFunction, encodedArgs, selector);
};
}

@@ -71,0 +85,0 @@ }

export { Contract } from './Contract';
export { Instance } from './Instance';
export { Transaction } from './Transaction';
export { Parameter, SignatureTemplate, Sig } from './Parameter';
export { Artifacts, Artifact, AbiFunction, AbiInput, } from 'cashc';
export { Utxo, Recipient, SignatureAlgorithm, HashType, } from './interfaces';
export { Argument } from './Argument';
export { default as SignatureTemplate } from './SignatureTemplate';
export { Artifacts, Artifact, AbiFunction, AbiInput, CashCompiler, } from 'cashc';
export { Utxo, Recipient, SignatureAlgorithm, HashType, Network, } from './interfaces';
export * from './Errors';
export * from './network';

@@ -8,15 +8,15 @@ "use strict";

exports.Contract = Contract_1.Contract;
var Instance_1 = require("./Instance");
exports.Instance = Instance_1.Instance;
var Transaction_1 = require("./Transaction");
exports.Transaction = Transaction_1.Transaction;
var Parameter_1 = require("./Parameter");
exports.SignatureTemplate = Parameter_1.SignatureTemplate;
exports.Sig = Parameter_1.Sig;
var SignatureTemplate_1 = require("./SignatureTemplate");
exports.SignatureTemplate = SignatureTemplate_1.default;
var cashc_1 = require("cashc");
exports.Artifacts = cashc_1.Artifacts;
exports.CashCompiler = cashc_1.CashCompiler;
var interfaces_1 = require("./interfaces");
exports.SignatureAlgorithm = interfaces_1.SignatureAlgorithm;
exports.HashType = interfaces_1.HashType;
exports.Network = interfaces_1.Network;
__export(require("./Errors"));
__export(require("./network"));
//# sourceMappingURL=index.js.map

@@ -1,13 +0,11 @@

/// <reference types="node" />
import { ECPair } from 'bitcoincashjs-lib';
import SignatureTemplate from './SignatureTemplate';
export interface Utxo {
txid: string;
vout: number;
amount: number;
satoshis: number;
}
export interface UtxoWithKeyPair extends Utxo {
keypair: ECPair;
export interface SignableUtxo extends Utxo {
template: SignatureTemplate;
}
export declare function isUtxoWithKeyPair(utxo: Utxo): utxo is UtxoWithKeyPair;
export declare function isSignableUtxo(utxo: Utxo): utxo is SignableUtxo;
export interface Recipient {

@@ -18,34 +16,5 @@ to: string;

export interface Output {
to: string | Buffer;
to: string | Uint8Array;
amount: number;
}
export interface ScriptSigDetails {
asm: string;
hex: string;
}
export interface TxnDetailValueIn {
cashAddress: string;
legacyAddress: string;
n: number;
scriptSig: ScriptSigDetails;
sequence: number;
txid: string;
value: number;
vout: number;
}
export interface ScriptPubKeyDetails {
addresses: string[];
cashAddrs: string[];
asm: string;
hex: string;
type: string;
}
export interface TxnDetailValueOut {
n: number;
scriptPubKey: ScriptPubKeyDetails;
spendHeight: null | number;
spendIndex: null | number;
spendTxId: null | number;
value: string;
}
export declare enum SignatureAlgorithm {

@@ -61,1 +30,6 @@ ECDSA = 0,

}
export declare const Network: {
MAINNET: "mainnet";
TESTNET: "testnet";
};
export declare type Network = (typeof Network)[keyof typeof Network];
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function isUtxoWithKeyPair(utxo) {
return 'keypair' in utxo;
function isSignableUtxo(utxo) {
return 'template' in utxo;
}
exports.isUtxoWithKeyPair = isUtxoWithKeyPair;
exports.isSignableUtxo = isSignableUtxo;
var SignatureAlgorithm;

@@ -19,2 +19,9 @@ (function (SignatureAlgorithm) {

})(HashType = exports.HashType || (exports.HashType = {}));
// Weird setup to allow both Enum parameters, as well as literal strings
// https://stackoverflow.com/questions/51433319/typescript-constructor-accept-string-for-enum
const literal = (l) => l;
exports.Network = {
MAINNET: literal('mainnet'),
TESTNET: literal('testnet'),
};
//# sourceMappingURL=interfaces.js.map

@@ -1,16 +0,13 @@

/// <reference types="node" />
import { ECPair } from 'bitcoincashjs-lib';
import { TxnDetailsResult } from 'bitcoin-com-rest';
import { Transaction as LibauthTransaction } from '@bitauth/libauth';
import { Script, AbiFunction } from 'cashc';
import { SignatureTemplate } from './Parameter';
import { Utxo, Recipient } from './interfaces';
import NetworkProvider from './network/NetworkProvider';
import SignatureTemplate from './SignatureTemplate';
export declare class Transaction {
private address;
private network;
private provider;
private redeemScript;
private abiFunction;
private parameters;
private args;
private selector?;
private bitbox;
private builder;
private inputs;

@@ -23,7 +20,7 @@ private outputs;

private minChange;
constructor(address: string, network: string, redeemScript: Script, abiFunction: AbiFunction, parameters: (Buffer | SignatureTemplate)[], selector?: number | undefined);
constructor(address: string, provider: NetworkProvider, redeemScript: Script, abiFunction: AbiFunction, args: (Uint8Array | SignatureTemplate)[], selector?: number | undefined);
from(input: Utxo): this;
from(inputs: Utxo[]): this;
experimentalFromP2PKH(input: Utxo, keypair: ECPair): this;
experimentalFromP2PKH(inputs: Utxo[], keypair: ECPair): this;
experimentalFromP2PKH(input: Utxo, template: SignatureTemplate): this;
experimentalFromP2PKH(inputs: Utxo[], template: SignatureTemplate): this;
to(to: string, amount: number): this;

@@ -37,4 +34,6 @@ to(outputs: Recipient[]): this;

withMinChange(minChange: number): this;
withoutChange(): this;
build(): Promise<string>;
send(): Promise<TxnDetailsResult>;
send(): Promise<LibauthTransaction>;
send(raw: true): Promise<string>;
private getTxDetails;

@@ -41,0 +40,0 @@ meep(): Promise<string>;

@@ -15,17 +15,17 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
const libauth_1 = require("@bitauth/libauth");
const delay_1 = __importDefault(require("delay"));
const Parameter_1 = require("./Parameter");
const BITBOX_1 = require("./BITBOX");
const cashc_1 = require("cashc");
const interfaces_1 = require("./interfaces");
const util_1 = require("./util");
const constants_1 = require("./constants");
const cramer = require('cramer-bch');
const bch = require('trout-bch');
const SignatureTemplate_1 = __importDefault(require("./SignatureTemplate"));
const bip68 = require('bip68');
class Transaction {
constructor(address, network, redeemScript, abiFunction, parameters, selector) {
constructor(address, provider, redeemScript, abiFunction, args, selector) {
this.address = address;
this.network = network;
this.provider = provider;
this.redeemScript = redeemScript;
this.abiFunction = abiFunction;
this.parameters = parameters;
this.args = args;
this.selector = selector;

@@ -37,4 +37,2 @@ this.inputs = [];

this.minChange = constants_1.DUST_LIMIT;
this.bitbox = BITBOX_1.bitbox[network];
this.builder = new this.bitbox.TransactionBuilder(this.network);
}

@@ -48,7 +46,7 @@ from(inputOrInputs) {

}
experimentalFromP2PKH(inputOrInputs, keypair) {
experimentalFromP2PKH(inputOrInputs, template) {
if (!Array.isArray(inputOrInputs)) {
inputOrInputs = [inputOrInputs];
}
inputOrInputs = inputOrInputs.map(input => (Object.assign(Object.assign({}, input), { keypair })));
inputOrInputs = inputOrInputs.map(input => (Object.assign(Object.assign({}, input), { template })));
this.inputs = this.inputs.concat(inputOrInputs);

@@ -74,3 +72,3 @@ return this;

withAge(age) {
this.sequence = this.builder.bip68.encode({ blocks: age });
this.sequence = bip68.encode({ blocks: age });
return this;

@@ -94,72 +92,83 @@ }

}
withoutChange() {
return this.withMinChange(Number.MAX_VALUE);
}
build() {
return __awaiter(this, void 0, void 0, function* () {
this.locktime = this.locktime || (yield this.bitbox.Blockchain.getBlockCount());
this.builder.setLockTime(this.locktime);
this.locktime = this.locktime || (yield this.provider.getBlockHeight());
yield this.setInputsAndOutputs();
this.inputs.forEach((utxo) => {
this.builder.addInput(utxo.txid, utxo.vout, this.sequence);
const secp256k1 = yield libauth_1.instantiateSecp256k1();
const bytecode = cashc_1.Data.scriptToBytecode(this.redeemScript);
const inputs = this.inputs.map(utxo => ({
outpointIndex: utxo.vout,
outpointTransactionHash: libauth_1.hexToBin(utxo.txid),
sequenceNumber: this.sequence,
unlockingBytecode: new Uint8Array(),
}));
const outputs = this.outputs.map((output) => {
const lockingBytecode = typeof output.to === 'string'
? util_1.addressToLockScript(output.to)
: output.to;
const satoshis = libauth_1.bigIntToBinUint64LE(BigInt(output.amount));
return { lockingBytecode, satoshis };
});
this.outputs.forEach((output) => {
this.builder.addOutput(output.to, output.amount);
});
// Vout is a misnomer used in BITBOX, should be vin
const transaction = {
inputs,
locktime: this.locktime,
outputs,
version: 2,
};
const inputScripts = [];
// Convert all SignatureTemplate objects to valid tx signatures for current tx
const tx = this.builder.transaction.buildIncomplete();
this.inputs.forEach((utxo, vin) => {
// UTXO's with key pairs are signed with the key pair using P2PKH
if (interfaces_1.isUtxoWithKeyPair(utxo)) {
const pubkey = utxo.keypair.getPublicKeyBuffer();
const pubkeyHash = bch.crypto.hash160(pubkey);
const prevOutScript = bch.script.pubKeyHash.output.encode(pubkeyHash);
const hashtype = interfaces_1.HashType.SIGHASH_ALL | tx.constructor.SIGHASH_BITCOINCASHBIP143;
const sighash = tx.hashForCashSignature(vin, prevOutScript, utxo.satoshis, hashtype);
const signature = utxo.keypair
.sign(sighash, interfaces_1.SignatureAlgorithm.SCHNORR)
.toScriptSignature(hashtype, interfaces_1.SignatureAlgorithm.SCHNORR);
const inputScript = bch.script.pubKeyHash.input.encode(signature, pubkey);
inputScripts.push({ vout: vin, script: inputScript });
this.inputs.forEach((utxo, i) => {
// UTXO's with signature templates are signed using P2PKH
if (interfaces_1.isSignableUtxo(utxo)) {
const pubkey = utxo.template.getPublicKey(secp256k1);
const pubkeyHash = util_1.hash160(pubkey);
const addressContents = { payload: pubkeyHash, type: libauth_1.AddressType.p2pkh };
const prevOutScript = libauth_1.addressContentsToLockingBytecode(addressContents);
const hashtype = utxo.template.getHashType();
const preimage = util_1.createSighashPreimage(transaction, utxo, i, prevOutScript, hashtype);
const sighash = util_1.sha256(util_1.sha256(preimage));
const signature = utxo.template.generateSignature(sighash, secp256k1);
const inputScript = cashc_1.Data.scriptToBytecode([signature, pubkey]);
inputScripts.push(inputScript);
return;
}
let covenantHashType = -1;
const completePs = this.parameters.map((p) => {
if (!(p instanceof Parameter_1.SignatureTemplate))
return p;
const hashtype = p.hashtype | tx.constructor.SIGHASH_BITCOINCASHBIP143;
const completeArgs = this.args.map((arg) => {
if (!(arg instanceof SignatureTemplate_1.default))
return arg;
// First signature is used for sighash preimage (maybe not the best way)
if (covenantHashType < 0)
covenantHashType = hashtype;
const sighash = tx.hashForCashSignature(vin, bch.script.compile(this.redeemScript), utxo.satoshis, hashtype);
return p.keypair
.sign(sighash, interfaces_1.SignatureAlgorithm.SCHNORR)
.toScriptSignature(hashtype, interfaces_1.SignatureAlgorithm.SCHNORR);
covenantHashType = arg.getHashType();
const preimage = util_1.createSighashPreimage(transaction, utxo, i, bytecode, arg.getHashType());
const sighash = util_1.sha256(util_1.sha256(preimage));
return arg.generateSignature(sighash, secp256k1);
});
// This is shitty because sigHashPreimageBuf is only in James Cramer's fork
// Will fix once it gets merged into main bitcoincashjs-lib
const preimageTx = cramer.Transaction.fromHex(tx.toHex());
const prevout = bch.script.compile(this.redeemScript);
const preimage = this.abiFunction.covenant
? preimageTx.sigHashPreimageBuf(vin, prevout, utxo.satoshis, covenantHashType)
? util_1.createSighashPreimage(transaction, utxo, i, bytecode, covenantHashType)
: undefined;
const inputScript = util_1.createInputScript(this.redeemScript, completePs, this.selector, preimage);
inputScripts.push({ vout: vin, script: inputScript });
const inputScript = util_1.createInputScript(this.redeemScript, completeArgs, this.selector, preimage);
inputScripts.push(inputScript);
});
this.builder.addInputScripts(inputScripts);
return this.builder.build().toHex();
inputScripts.forEach((script, i) => {
transaction.inputs[i].unlockingBytecode = script;
});
return libauth_1.binToHex(libauth_1.encodeTransaction(transaction));
});
}
send() {
send(raw) {
return __awaiter(this, void 0, void 0, function* () {
const tx = yield this.build();
try {
const txid = yield this.bitbox.RawTransactions.sendRawTransaction(tx);
return this.getTxDetails(txid);
const txid = yield this.provider.sendRawTransaction(tx);
return raw ? this.getTxDetails(txid, raw) : this.getTxDetails(txid);
}
catch (e) {
throw util_1.buildError(e.error, util_1.meep(tx, this.inputs, this.redeemScript));
const reason = e.error || e.message;
throw util_1.buildError(reason, util_1.meep(tx, this.inputs, this.redeemScript));
}
});
}
getTxDetails(txid) {
getTxDetails(txid, raw) {
return __awaiter(this, void 0, void 0, function* () {

@@ -169,3 +178,4 @@ while (true) {

try {
return yield this.bitbox.Transaction.details(txid);
const txHex = yield this.provider.getRawTransaction(txid);
return raw ? txHex : libauth_1.decodeTransaction(libauth_1.hexToBin(txHex));
}

@@ -189,9 +199,11 @@ catch (ignored) {

}
// Use a placeholder script with 65-length Buffer in the place of signatures
// and a correctly sized preimage Buffer if the function is a covenant
// for correct size calculation of inputs
// Replace all SignatureTemplate with 65-length placeholder Uint8Arrays
const placeholderArgs = this.args.map(arg => (arg instanceof SignatureTemplate_1.default ? util_1.placeholder(65) : arg));
// Create a placeholder preimage of the correct size
const placeholderPreimage = this.abiFunction.covenant
? Buffer.alloc(util_1.getPreimageSize(bch.script.compile(this.redeemScript)), 0)
? util_1.placeholder(util_1.getPreimageSize(cashc_1.Data.scriptToBytecode(this.redeemScript)))
: undefined;
const placeholderScript = util_1.createInputScript(this.redeemScript, this.parameters.map(p => (p instanceof Parameter_1.SignatureTemplate ? Buffer.alloc(65, 0) : p)), this.selector, placeholderPreimage);
// Create a placeholder input script for size calculation using the placeholder
// arguments and correctly sized placeholder preimage
const placeholderScript = util_1.createInputScript(this.redeemScript, placeholderArgs, this.selector, placeholderPreimage);
// Add one extra byte per input to over-estimate tx-in count

@@ -214,5 +226,7 @@ const inputSize = util_1.getInputSize(placeholderScript) + 1;

else {
// If inputs are not defined yet, we retrieve the contract's UTXOs
// and perform UTXO selection
const { utxos } = yield this.bitbox.Address.utxo(this.address);
// If inputs are not defined yet, we retrieve the contract's UTXOs and perform selection
const utxos = yield this.provider.getUtxos(this.address);
// We sort the UTXOs mainly so there is consistent behaviour between network providers
// even if they report UTXOs in a different order
utxos.sort((a, b) => b.satoshis - a.satoshis);
for (const utxo of utxos) {

@@ -219,0 +233,0 @@ this.inputs.push(utxo);

@@ -1,13 +0,32 @@

/// <reference types="node" />
import { Script } from 'cashc';
import { Transaction } from '@bitauth/libauth';
import { Utxo, Output } from './interfaces';
import { FailedTransactionError } from './Errors';
export declare function getInputSize(script: Buffer): number;
export declare function getPreimageSize(script: Buffer): number;
export declare function getInputSize(inputScript: Uint8Array): number;
export declare function getPreimageSize(script: Uint8Array): number;
export declare function getTxSizeWithoutInputs(outputs: Output[]): number;
export declare function placeholder(size: number): Uint8Array;
export declare function countOpcodes(script: Script): number;
export declare function calculateBytesize(script: Script): number;
export declare function createInputScript(redeemScript: Script, encodedParameters: Buffer[], selector?: number, preimage?: Buffer): Buffer;
export declare function createInputScript(redeemScript: Script, encodedArgs: Uint8Array[], selector?: number, preimage?: Uint8Array): Uint8Array;
export declare function createOpReturnOutput(opReturnData: string[]): Output;
export declare function createSighashPreimage(transaction: Transaction, input: {
satoshis: number;
}, inputIndex: number, coveredBytecode: Uint8Array, hashtype: number): Uint8Array;
export declare function buildError(reason: string, meepStr: string): FailedTransactionError;
export declare function sha512(payload: Uint8Array): Uint8Array;
export declare function sha256(payload: Uint8Array): Uint8Array;
export declare function ripemd160(payload: Uint8Array): Uint8Array;
export declare function hash160(payload: Uint8Array): Uint8Array;
export declare function meep(tx: any, utxos: Utxo[], script: Script): string;
export declare function scriptToAddress(script: Script, network: string): string;
export declare function scriptToLockingBytecode(script: Script): Uint8Array;
/**
* Helper function to convert an address to a locking script
*
* @param address Address to convert to locking script
*
* @returns a locking script corresponding to the passed address
*/
export declare function addressToLockScript(address: string): Uint8Array;
export declare function getNetworkPrefix(network: string): 'bitcoincash' | 'bchtest';
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const cashc_1 = require("cashc");
const libauth_1 = require("@bitauth/libauth");
const hash_js_1 = __importDefault(require("hash.js"));
const interfaces_1 = require("./interfaces");
const constants_1 = require("./constants");
const Errors_1 = require("./Errors");
const bch = require('trout-bch');
// ////////// SIZE CALCULATIONS ///////////////////////////////////////////////
function getInputSize(script) {
const scriptSize = script.byteLength;
function getInputSize(inputScript) {
const scriptSize = inputScript.byteLength;
const varIntSize = scriptSize > 252 ? 3 : 1;

@@ -50,2 +55,6 @@ return 32 + 4 + varIntSize + scriptSize + 4;

exports.getTxSizeWithoutInputs = getTxSizeWithoutInputs;
function placeholder(size) {
return new Uint8Array(size).fill(0);
}
exports.placeholder = placeholder;
function countOpcodes(script) {

@@ -59,9 +68,9 @@ return script

function calculateBytesize(script) {
return bch.script.compile(script).byteLength;
return cashc_1.Data.scriptToBytecode(script).byteLength;
}
exports.calculateBytesize = calculateBytesize;
// ////////// BUILD OBJECTS ///////////////////////////////////////////////////
function createInputScript(redeemScript, encodedParameters, selector, preimage) {
// Create unlock script / redeemScriptSig
const unlockScript = encodedParameters.reverse();
function createInputScript(redeemScript, encodedArgs, selector, preimage) {
// Create unlock script / redeemScriptSig (add potential preimage and selector)
const unlockScript = encodedArgs.reverse();
if (preimage !== undefined)

@@ -71,4 +80,5 @@ unlockScript.push(preimage);

unlockScript.push(cashc_1.Data.encodeInt(selector));
// Create total input script / scriptSig
return bch.script.scriptHash.input.encode(bch.script.compile(unlockScript), bch.script.compile(redeemScript));
// Create input script and compile it to bytecode
const inputScript = [...unlockScript, cashc_1.Data.scriptToBytecode(redeemScript)];
return cashc_1.Data.scriptToBytecode(inputScript);
}

@@ -79,3 +89,3 @@ exports.createInputScript = createInputScript;

cashc_1.Op.OP_RETURN,
...opReturnData.map((output) => toBuffer(output)),
...opReturnData.map((output) => toBin(output)),
];

@@ -85,7 +95,32 @@ return { to: encodeNullDataScript(script), amount: 0 };

exports.createOpReturnOutput = createOpReturnOutput;
function toBuffer(output) {
function toBin(output) {
const data = output.replace(/^0x/, '');
const format = data === output ? 'utf8' : 'hex';
return Buffer.from(data, format);
const encode = data === output ? libauth_1.utf8ToBin : libauth_1.hexToBin;
return encode(data);
}
function createSighashPreimage(transaction, input, inputIndex, coveredBytecode, hashtype) {
const state = libauth_1.createTransactionContextCommon({
inputIndex,
sourceOutput: { satoshis: libauth_1.bigIntToBinUint64LE(BigInt(input.satoshis)) },
spendingTransaction: transaction,
});
const sighashPreimage = libauth_1.generateSigningSerializationBCH({
correspondingOutput: state.correspondingOutput,
coveredBytecode,
forkId: new Uint8Array([0, 0, 0]),
locktime: state.locktime,
outpointIndex: state.outpointIndex,
outpointTransactionHash: state.outpointTransactionHash,
outputValue: state.outputValue,
sequenceNumber: state.sequenceNumber,
sha256: { hash: sha256 },
signingSerializationType: new Uint8Array([hashtype]),
transactionOutpoints: state.transactionOutpoints,
transactionOutputs: state.transactionOutputs,
transactionSequenceNumbers: state.transactionSequenceNumbers,
version: 2,
});
return sighashPreimage;
}
exports.createSighashPreimage = createSighashPreimage;
function buildError(reason, meepStr) {

@@ -118,47 +153,78 @@ const require = [

}
// ////////// HASH FUNCTIONS //////////////////////////////////////////////////
function sha512(payload) {
return Uint8Array.from(hash_js_1.default.sha512().update(payload).digest());
}
exports.sha512 = sha512;
function sha256(payload) {
return Uint8Array.from(hash_js_1.default.sha256().update(payload).digest());
}
exports.sha256 = sha256;
function ripemd160(payload) {
return Uint8Array.from(hash_js_1.default.ripemd160().update(payload).digest());
}
exports.ripemd160 = ripemd160;
function hash160(payload) {
return ripemd160(sha256(payload));
}
exports.hash160 = hash160;
// ////////// MISC ////////////////////////////////////////////////////////////
function meep(tx, utxos, script) {
const scriptHash = bch.crypto.hash160(bch.script.compile(script));
const scriptPubkey = bch.script.scriptHash.output.encode(scriptHash).toString('hex');
const scriptPubkey = libauth_1.binToHex(scriptToLockingBytecode(script));
return `meep debug --tx=${tx} --idx=0 --amt=${utxos[0].satoshis} --pkscript=${scriptPubkey}`;
}
exports.meep = meep;
function scriptToAddress(script, network) {
const lockingBytecode = scriptToLockingBytecode(script);
const prefix = getNetworkPrefix(network);
const address = libauth_1.lockingBytecodeToCashAddress(lockingBytecode, prefix);
return address;
}
exports.scriptToAddress = scriptToAddress;
function scriptToLockingBytecode(script) {
const scriptHash = hash160(cashc_1.Data.scriptToBytecode(script));
const addressContents = { payload: scriptHash, type: libauth_1.AddressType.p2sh };
const lockingBytecode = libauth_1.addressContentsToLockingBytecode(addressContents);
return lockingBytecode;
}
exports.scriptToLockingBytecode = scriptToLockingBytecode;
/**
* Helper function to convert an address to a locking script
*
* @param address Address to convert to locking script
*
* @returns a locking script corresponding to the passed address
*/
function addressToLockScript(address) {
const result = libauth_1.cashAddressToLockingBytecode(address);
if (typeof result === 'string')
throw new Error(result);
return result.bytecode;
}
exports.addressToLockScript = addressToLockScript;
function getNetworkPrefix(network) {
return network === interfaces_1.Network.MAINNET ? 'bitcoincash' : 'bchtest';
}
exports.getNetworkPrefix = getNetworkPrefix;
// ////////////////////////////////////////////////////////////////////////////
// For encoding OP_RETURN data (doesn't require BIP62.3)
// These functions are a mash-up between those found in these libs:
// - https://github.com/simpleledger/slpjs/blob/master/lib/utils.ts
// - https://github.com/Bitcoin-com/bitcoincashjs-lib/blob/master/src/script.js
// For encoding OP_RETURN data (doesn't require BIP62.3 / MINIMALDATA)
function encodeNullDataScript(chunks) {
const bufferSize = chunks.reduce((acc, chunk) => {
if (Buffer.isBuffer(chunk)) {
return libauth_1.flattenBinArray(chunks.map((chunk) => {
if (chunk instanceof Uint8Array) {
const pushdataOpcode = getPushDataOpcode(chunk);
return acc + chunk.length + pushdataOpcode.length;
return new Uint8Array([...pushdataOpcode, ...chunk]);
}
return acc + 1;
}, 0);
const buffer = Buffer.allocUnsafe(bufferSize);
let offset = 0;
chunks.forEach((chunk) => {
if (Buffer.isBuffer(chunk)) {
const pushdataOpcode = getPushDataOpcode(chunk);
pushdataOpcode.copy(buffer, offset);
offset += pushdataOpcode.length;
chunk.copy(buffer, offset);
offset += chunk.length;
}
else {
buffer.writeUInt8(chunk, offset);
offset += 1;
return new Uint8Array([chunk]);
}
});
return buffer;
}));
}
function getPushDataOpcode(data) {
const { length } = data;
if (length === 0)
return Buffer.from([0x4c, 0x00]);
if (length < 76)
return Buffer.from([length]);
if (length < 256)
return Buffer.from([0x4c, length]);
const { byteLength } = data;
if (byteLength === 0)
return Uint8Array.from([0x4c, 0x00]);
if (byteLength < 76)
return Uint8Array.from([byteLength]);
if (byteLength < 256)
return Uint8Array.from([0x4c, byteLength]);
throw Error('Pushdata too large');

@@ -165,0 +231,0 @@ }

{
"name": "cashscript",
"version": "0.5.0",
"description": "Easily write and interact with Bitcoin Cash contracts",
"version": "0.4.4",
"author": "Rosco Kalis <roscokalis@gmail.com>",
"keywords": [
"bitcoin cash",
"cashscript",
"sdk",
"smart contracts"
],
"homepage": "https://cashscript.org",
"bugs": {
"url": "https://github.com/Bitcoin-com/cashscript/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/Bitcoin-com/cashscript.git"
},
"license": "MIT",
"author": "Rosco Kalis <roscokalis@gmail.com>",
"contributors": [
"Gabriel Cardona <gabriel@bitcoin.com>"
],
"dependencies": {
"bitbox-sdk": "^8.8.0",
"cashc": "^0.4.4",
"cramer-bch": "https://github.com/jcramer/bitcoincashjs-lib",
"delay": "^4.3.0",
"bitcoincash-ops": "github:christroutner/bitcoincash-ops",
"trout-bch": "github:christroutner/bitcoincashjs-lib#34f23671b42f0ebcbeba9f1f9e7bcdba7c50d55b"
},
"devDependencies": {
"bignumber.js": "^9.0.0",
"eslint": "^6.6.0",
"jest": "^25.1.0",
"ts-jest": "^25.1.0",
"typescript": "3.7.5"
},
"main": "dist/index",
"types": "dist/index",
"directories": {

@@ -31,15 +30,2 @@ "lib": "src",

},
"homepage": "https://cashscript.org",
"keywords": [
"bitcoin cash",
"cashscript",
"sdk",
"smart contracts"
],
"license": "MIT",
"main": "dist/index",
"repository": {
"type": "git",
"url": "git+https://github.com/Bitcoin-com/cashscript.git"
},
"scripts": {

@@ -51,5 +37,22 @@ "build": "npm run clean && npm run compile",

"prepare": "npm run build",
"prepublishOnly": "npm run lint",
"test": "jest --config=../../jest.config.js packages/cashscript"
},
"types": "dist/index"
"dependencies": {
"@bitauth/libauth": "^1.17.1",
"bip68": "^1.0.4",
"cashc": "^0.5.0",
"delay": "^4.3.0",
"electrum-cash": "^2.0.2",
"hash.js": "^1.1.7"
},
"devDependencies": {
"@psf/bch-js": "^3.5.3",
"bignumber.js": "^9.0.0",
"bitbox-sdk": "^8.8.0",
"eslint": "^6.6.0",
"jest": "^25.1.0",
"ts-jest": "^25.1.0",
"typescript": "3.7.5"
}
}

@@ -11,3 +11,3 @@ # CashScript

See the [GitHub repository](https://github.com/Bitcoin-com/cashscript) or the [CashScript website](https://cashscript.org) for full documentation and usage examples.
See the [GitHub repository](https://github.com/Bitcoin-com/cashscript) and the [CashScript website](https://cashscript.org) for full documentation and usage examples.

@@ -27,7 +27,7 @@ ## The CashScript Language

```ts
import { Contract, ... } from 'cashscript';
import { Contract, CashCompiler, ... } from 'cashscript';
```
```js
const { Contract, ... } = require('cashscript');
const { Contract, CashCompiler, ... } = require('cashscript');
```

@@ -40,19 +40,23 @@

// Compile the P2PKH contract
const P2PKH = Contract.compile('./p2pkh.cash', 'mainnet');
const P2PKH = CashCompiler.compileFile('./p2pkh.cash');
// Instantiate a new P2PKH contract with constructor arguments: { pkh: pkh }
const instance = P2PKH.new(pkh);
// Instantiate a network provider for CashScript's network operations
const provider = new ElectrumNetworkProvider('mainnet');
// Create a new P2PKH contract with constructor arguments: { pkh: pkh }
const contract = new Contract(P2PKH, [pkh], provider);
// Get contract balance & output address + balance
console.log('contract address:', instance.address);
console.log('contract balance:', await instance.getBalance());
console.log('contract address:', contract.address);
console.log('contract balance:', await contract.getBalance());
// Call the spend function with the owner's signature
// And use it to send 0. 000 100 00 BCH back to the contract's address
const txDetails = await instance.functions
const txDetails = await contract.functions
.spend(pk, new SignatureTemplate(keypair))
.to(instance.address, 10000)
.to(contract.address, 10000)
.send();
console.log(txDetails);
...
```
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc