diff --git a/src/script.ts b/src/script.ts index 514e992..98b018a 100644 --- a/src/script.ts +++ b/src/script.ts @@ -10,37 +10,49 @@ const OPS = require('bitcoin-ops') const REVERSE_OPS = require('bitcoin-ops/map') const OP_INT_BASE = OPS.OP_RESERVED // OP_1 - 1 -function isOPInt (value) { +function isOPInt (value:number): boolean { return types.Number(value) && ((value === OPS.OP_0) || (value >= OPS.OP_1 && value <= OPS.OP_16) || (value === OPS.OP_1NEGATE)) } -function isPushOnlyChunk (value) { - return types.Buffer(value) || isOPInt(value) +function isPushOnlyChunk (value: number | Buffer): boolean { + return types.Buffer(value) || isOPInt(value) } -function isPushOnly (value) { +export function isPushOnly (value: Array) { return types.Array(value) && value.every(isPushOnlyChunk) } -function asMinimalOP (buffer) { +function asMinimalOP (buffer: Buffer): number | void { if (buffer.length === 0) return OPS.OP_0 if (buffer.length !== 1) return if (buffer[0] >= 1 && buffer[0] <= 16) return OP_INT_BASE + buffer[0] if (buffer[0] === 0x81) return OPS.OP_1NEGATE } -function compile (chunks) { +function chunksIsBuffer(buf: Buffer | Array): buf is Buffer { + return Buffer.isBuffer(buf) +} + +function chunksIsArray(buf: Buffer | Array): buf is Array { + return types.Array(buf) +} + +function singleChunkIsBuffer(buf: number | Buffer): buf is Buffer { + return Buffer.isBuffer(buf) +} + +export function compile (chunks: Buffer | Array): Buffer { // TODO: remove me - if (Buffer.isBuffer(chunks)) return chunks + if (chunksIsBuffer(chunks)) return chunks typeforce(types.Array, chunks) - const bufferSize = chunks.reduce(function (accum, chunk) { + const bufferSize = chunks.reduce(function (accum: number, chunk) { // data chunk - if (Buffer.isBuffer(chunk)) { + if (singleChunkIsBuffer(chunk)) { // adhere to BIP62.3, minimal push policy if (chunk.length === 1 && asMinimalOP(chunk) !== undefined) { return accum + 1 @@ -58,7 +70,7 @@ function compile (chunks) { chunks.forEach(function (chunk) { // data chunk - if (Buffer.isBuffer(chunk)) { + if (singleChunkIsBuffer(chunk)) { // adhere to BIP62.3, minimal push policy const opcode = asMinimalOP(chunk) if (opcode !== undefined) { @@ -82,9 +94,9 @@ function compile (chunks) { return buffer } -function decompile (buffer) { +export function decompile (buffer: Buffer | Array): Array { // TODO: remove me - if (types.Array(buffer)) return buffer + if (chunksIsArray(buffer)) return buffer typeforce(types.Buffer, buffer) @@ -127,17 +139,17 @@ function decompile (buffer) { return chunks } -function toASM (chunks) { - if (Buffer.isBuffer(chunks)) { +export function toASM (chunks: Buffer | Array): string { + if (chunksIsBuffer(chunks)) { chunks = decompile(chunks) } return chunks.map(function (chunk) { // data? - if (Buffer.isBuffer(chunk)) { + if (singleChunkIsBuffer(chunk)) { const op = asMinimalOP(chunk) if (op === undefined) return chunk.toString('hex') - chunk = op + chunk = op } // opcode! @@ -145,7 +157,7 @@ function toASM (chunks) { }).join(' ') } -function fromASM (asm) { +export function fromASM (asm: string): Buffer { typeforce(types.String, asm) return compile(asm.split(' ').map(function (chunkStr) { @@ -158,49 +170,35 @@ function fromASM (asm) { })) } -function toStack (chunks) { +export function toStack (chunks: Buffer | Array): Array { chunks = decompile(chunks) typeforce(isPushOnly, chunks) return chunks.map(function (op) { - if (Buffer.isBuffer(op)) return op + if (singleChunkIsBuffer(op)) return op if (op === OPS.OP_0) return Buffer.allocUnsafe(0) return scriptNumber.encode(op - OP_INT_BASE) }) } -function isCanonicalPubKey (buffer) { +export function isCanonicalPubKey (buffer: Buffer): boolean { return ecc.isPoint(buffer) } -function isDefinedHashType (hashType) { +export function isDefinedHashType (hashType: number): boolean { const hashTypeMod = hashType & ~0x80 // return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE return hashTypeMod > 0x00 && hashTypeMod < 0x04 } -function isCanonicalScriptSignature (buffer) { +export function isCanonicalScriptSignature (buffer: Buffer): boolean { if (!Buffer.isBuffer(buffer)) return false if (!isDefinedHashType(buffer[buffer.length - 1])) return false return bip66.check(buffer.slice(0, -1)) } -module.exports = { - compile: compile, - decompile: decompile, - fromASM: fromASM, - toASM: toASM, - toStack: toStack, - - number: require('./script_number'), - signature: require('./script_signature'), - - isCanonicalPubKey: isCanonicalPubKey, - isCanonicalScriptSignature: isCanonicalScriptSignature, - isPushOnly: isPushOnly, - isDefinedHashType: isDefinedHashType -} -export {} +export const number = require('./script_number') +export const signature = require('./script_signature') diff --git a/src/script_number.ts b/src/script_number.ts index 4df4704..8178c95 100644 --- a/src/script_number.ts +++ b/src/script_number.ts @@ -1,6 +1,6 @@ const Buffer = require('safe-buffer').Buffer -function decode (buffer, maxLength, minimal) { +export function decode (buffer: Buffer, maxLength?: number, minimal?: boolean): number { maxLength = maxLength || 4 minimal = minimal === undefined ? true : minimal @@ -41,7 +41,7 @@ function scriptNumSize (i) { : 0 } -function encode (number) { +export function encode (number: number): Buffer { let value = Math.abs(number) const size = scriptNumSize(value) const buffer = Buffer.allocUnsafe(size) @@ -60,9 +60,3 @@ function encode (number) { return buffer } - -module.exports = { - decode: decode, - encode: encode -} -export {} diff --git a/src/script_signature.ts b/src/script_signature.ts index b1f933a..fefd09d 100644 --- a/src/script_signature.ts +++ b/src/script_signature.ts @@ -4,7 +4,7 @@ const typeforce = require('typeforce') const types = require('./types') const ZERO = Buffer.alloc(1, 0) -function toDER (x) { +function toDER (x: Buffer): Buffer { let i = 0 while (x[i] === 0) ++i if (i === x.length) return ZERO @@ -13,7 +13,7 @@ function toDER (x) { return x } -function fromDER (x) { +function fromDER (x: Buffer): Buffer { if (x[0] === 0x00) x = x.slice(1) const buffer = Buffer.alloc(32, 0) const bstart = Math.max(0, 32 - x.length) @@ -21,8 +21,13 @@ function fromDER (x) { return buffer } +interface ScriptSignature { + signature: Buffer + hashType: number +} + // BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed) -function decode (buffer) { +export function decode (buffer: Buffer): ScriptSignature { const hashType = buffer.readUInt8(buffer.length - 1) const hashTypeMod = hashType & ~0x80 if (hashTypeMod <= 0 || hashTypeMod >= 4) throw new Error('Invalid hashType ' + hashType) @@ -37,7 +42,7 @@ function decode (buffer) { } } -function encode (signature, hashType) { +export function encode (signature: Buffer, hashType: number): Buffer { typeforce({ signature: types.BufferN(64), hashType: types.UInt8 @@ -57,9 +62,3 @@ function encode (signature, hashType) { hashTypeBuffer ]) } - -module.exports = { - decode: decode, - encode: encode -} -export {}