commit a31451c6cbf6f5c19912efdf92f7c87e1e69e129 Author: Luke Childs Date: Wed Nov 7 19:35:42 2018 +0700 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7fd69e0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +node_modules +.nyc_output +npm-debug.log +package-lock.json +yarn.lock diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..2bde09e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,8 @@ +language: node_js +node_js: + - '8' +script: npm test +after_success: npm run coverage +notifications: + email: + on_success: never diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a4daae1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Luke Childs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..c0e41f0 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# build-output-script + +> Builds a P2PKH Bitcoin transaction output script + +[![Build Status](https://travis-ci.org/lukechilds/build-output-script.svg?branch=master)](https://travis-ci.org/lukechilds/build-output-script) +[![Coverage Status](https://coveralls.io/repos/github/lukechilds/build-output-script/badge.svg?branch=master)](https://coveralls.io/github/lukechilds/build-output-script?branch=master) +[![npm](https://img.shields.io/npm/dm/build-output-script.svg)](https://www.npmjs.com/package/build-output-script) +[![npm](https://img.shields.io/npm/v/build-output-script.svg)](https://www.npmjs.com/package/build-output-script) + +Builds a P2PKH Bitcoin transaction output script from an array of P2PKH addresses and amounts. Will also work with any Bitcoin derived cryptocurrencies with a single byte pubkey hash prefix. + +## Install + +```shell +npm install build-output-script +``` + +## License + +MIT © Luke Childs diff --git a/package.json b/package.json new file mode 100644 index 0000000..745a459 --- /dev/null +++ b/package.json @@ -0,0 +1,45 @@ +{ + "name": "build-output-script", + "version": "0.0.0", + "description": "Builds a P2PKH Bitcoin transaction output script.", + "main": "src/index.js", + "engines": { + "node": ">=8" + }, + "scripts": { + "test": "xo && nyc ava", + "coverage": "nyc report --reporter=text-lcov | coveralls" + }, + "xo": { + "extends": "xo-lukechilds" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/lukechilds/build-output-script.git" + }, + "keywords": [ + "bitcoin", + "outputscript", + "output", + "script", + "build" + ], + "author": "Luke Childs (http://lukechilds.co.uk)", + "license": "MIT", + "bugs": { + "url": "https://github.com/lukechilds/build-output-script/issues" + }, + "homepage": "https://github.com/lukechilds/build-output-script#readme", + "devDependencies": { + "ava": "^0.25.0", + "coveralls": "^3.0.2", + "eslint-config-xo-lukechilds": "^1.0.1", + "nyc": "^13.1.0", + "xo": "^0.23.0" + }, + "dependencies": { + "bitcoin-ops": "^1.4.1", + "bs58check": "^2.1.2", + "varuint-bitcoin": "^1.1.0" + } +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..497456e --- /dev/null +++ b/src/index.js @@ -0,0 +1,50 @@ +const bs58check = require('bs58check'); +const { encode: numberToCompactSizeUInt } = require('varuint-bitcoin'); +const { OP_DUP, OP_HASH160, OP_EQUALVERIFY, OP_CHECKSIG } = require('bitcoin-ops'); + +const addressDecode = address => bs58check.decode(address).slice(1); + +const checkUInt53 = number => { + if (number < 0 || !Number.isSafeInteger(number)) { + throw new RangeError('value out of range'); + } +}; + +const numberToUInt64 = number => { + checkUInt53(number); + + const buffer = Buffer.alloc(8); + + buffer.writeUInt32LE(number >>> 0); + buffer.writeUInt32LE((number / 0x100000000) | 0, 4); + + return buffer; +}; + +const buildOutputScript = outputs => { + let outputScript = [...numberToCompactSizeUInt(outputs.length)]; + + for (const [address, value] of outputs) { + const pubkeyHash = addressDecode(address); + + const scriptPubKey = [ + OP_DUP, + OP_HASH160, + pubkeyHash.length, + ...pubkeyHash, + OP_EQUALVERIFY, + OP_CHECKSIG + ]; + + outputScript = [ + ...outputScript, + ...numberToUInt64(value), + ...numberToCompactSizeUInt(scriptPubKey.length), + ...scriptPubKey + ]; + } + + return Buffer.from(outputScript).toString('hex'); +}; + +module.exports = buildOutputScript; diff --git a/test/unit.js b/test/unit.js new file mode 100644 index 0000000..c10b075 --- /dev/null +++ b/test/unit.js @@ -0,0 +1,2 @@ +import test from 'ava'; +import buildOutputScript from '..';