├── lerna.json ├── packages ├── plugin │ ├── lib │ │ ├── index.js │ │ ├── host.js │ │ └── provider.js │ ├── test │ │ └── index.js │ ├── README.md │ └── package.json ├── transaction │ ├── test │ │ ├── mocks │ │ │ └── chain.js │ │ ├── input.js │ │ ├── output.js │ │ ├── sighash.js │ │ ├── script.js │ │ └── index.js │ ├── package.json │ ├── lib │ │ ├── output.js │ │ ├── script.js │ │ ├── input.js │ │ ├── sighash.js │ │ └── index.js │ ├── README.md │ └── package-lock.json ├── chain │ ├── README.md │ ├── test │ │ ├── index.js │ │ ├── fixtures │ │ │ ├── templates.js │ │ │ └── opcodes.js │ │ ├── opcode.js │ │ ├── template-collection.js │ │ └── opcode-collection.js │ ├── lib │ │ ├── index.js │ │ ├── opcode-collection.js │ │ ├── template-collection.js │ │ ├── opcode.js │ │ ├── standard-opcodes.js │ │ └── standard-templates.js │ └── package.json ├── keyring │ ├── lib │ │ └── index.js │ ├── package.json │ └── README.md ├── util │ ├── lib │ │ ├── bn.js │ │ ├── index.js │ │ ├── addr.js │ │ ├── format.js │ │ ├── buf.js │ │ ├── parser.js │ │ ├── reader.js │ │ └── writer.js │ ├── test │ │ ├── index.js │ │ ├── addr.js │ │ ├── bn.js │ │ ├── format.js │ │ ├── parser.js │ │ ├── writer.js │ │ └── reader.js │ ├── package.json │ └── package-lock.json ├── bsv │ ├── lib │ │ └── index.js │ ├── package.json │ └── README.md ├── cbor-plugin │ ├── README.md │ ├── lib │ │ ├── index.js │ │ └── transaction.js │ ├── package.json │ └── test │ │ └── index.js ├── msgpack-plugin │ ├── README.md │ ├── lib │ │ ├── index.js │ │ └── transaction.js │ ├── package.json │ └── test │ │ └── index.js ├── txo-plugin │ ├── lib │ │ ├── index.js │ │ └── transaction.js │ ├── README.md │ ├── test │ │ ├── index.js │ │ └── vectors.json │ └── package.json └── validation-plugin │ ├── lib │ ├── index.js │ └── transaction.js │ ├── package.json │ ├── README.md │ └── test │ └── index.js ├── package.json ├── testall.sh ├── LICENSE ├── .gitignore ├── README.md └── yarn.lock /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.1", 3 | "npmClient": "yarn", 4 | "useWorkspaces": true 5 | } 6 | -------------------------------------------------------------------------------- /packages/plugin/lib/index.js: -------------------------------------------------------------------------------- 1 | const Plugin = { 2 | Host: require('./host'), 3 | Provider: require('./provider') 4 | }; 5 | 6 | module.exports = Plugin; 7 | -------------------------------------------------------------------------------- /packages/plugin/test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Plugin = require('../lib'); 4 | 5 | describe('@keyring/plugin', () => { 6 | it('needs tests'); 7 | }); 8 | -------------------------------------------------------------------------------- /packages/transaction/test/mocks/chain.js: -------------------------------------------------------------------------------- 1 | class MockChain { 2 | constructor() {} 3 | templates() { 4 | return []; 5 | } 6 | } 7 | 8 | module.exports = MockChain; 9 | -------------------------------------------------------------------------------- /packages/chain/README.md: -------------------------------------------------------------------------------- 1 | # `@keyring/chain` 2 | 3 | > TODO: description 4 | 5 | ## Usage 6 | 7 | ``` 8 | const chain = require('@keyring/chain'); 9 | 10 | // TODO: DEMONSTRATE API 11 | ``` 12 | -------------------------------------------------------------------------------- /packages/keyring/lib/index.js: -------------------------------------------------------------------------------- 1 | const BSV = require('@keyring/bsv'); 2 | const Util = require('@keyring/Util'); 3 | 4 | const Keyring = { 5 | BSV, 6 | Util 7 | }; 8 | 9 | module.exports = Keyring; 10 | -------------------------------------------------------------------------------- /packages/util/lib/bn.js: -------------------------------------------------------------------------------- 1 | const BN = require('bn.js'); 2 | 3 | BN.from = (num) => { 4 | return new BN(num); 5 | }; 6 | 7 | BN.Zero = new BN(0); 8 | BN.One = new BN(1); 9 | 10 | BN.Byte = BN.One; 11 | BN.KB = new BN(1024); 12 | 13 | module.exports = BN; 14 | -------------------------------------------------------------------------------- /packages/util/lib/index.js: -------------------------------------------------------------------------------- 1 | const Util = { 2 | r: require('ramda'), 3 | bn: require('./bn'), 4 | buf: require('./buf'), 5 | addr: require('./addr'), 6 | format: require('./format'), 7 | Writer: require('./writer'), 8 | Reader: require('./reader'), 9 | Parser: require('./parser') 10 | }; 11 | 12 | module.exports = Util; 13 | -------------------------------------------------------------------------------- /packages/bsv/lib/index.js: -------------------------------------------------------------------------------- 1 | const Chain = require('@keyring/chain'); 2 | const Transaction = require('@keyring/transaction'); 3 | 4 | const BSV = new Chain({ 5 | dataMode: 'false-data' 6 | }); 7 | 8 | BSV.Transaction = Transaction.for(BSV); 9 | BSV.use = (provider, refresh) => { 10 | BSV.Transaction.use(provider, refresh); 11 | }; 12 | 13 | module.exports = BSV; 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@keyring/root", 3 | "version": "0.0.0", 4 | "description": "Blockchain Tools", 5 | "author": "BitBoss", 6 | "repository": "git@github.com:BitbossIO/keyring.git", 7 | "license": "MIT", 8 | "private": true, 9 | "main": "index.js", 10 | "workspaces": ["packages/*"], 11 | "devDependencies": { 12 | "lerna": "^3.10.7" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/keyring/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@keyring/keyring", 3 | "version": "0.2.0", 4 | "description": "Keyring base package", 5 | "main": "lib/index.js", 6 | "repository": "https://github.com/BitbossIO/keyring", 7 | "license": "MIT", 8 | "private": false, 9 | "devDependencies": { 10 | "chai": "^4.2.0", 11 | "mocha": "^5.2.0" 12 | }, 13 | "gitHead": "87c6e9b97dcce546d3633371c78bace73adab4a2" 14 | } 15 | -------------------------------------------------------------------------------- /packages/util/test/index.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const expect = chai.expect; 3 | 4 | const Util = require('../lib'); 5 | 6 | describe('Reader', () => { 7 | it('should include all utils', () => { 8 | expect(Util).to.have.all.keys( 9 | 'r', 10 | 'bn', 11 | 'buf', 12 | 'addr', 13 | 'format', 14 | 'Writer', 15 | 'Reader', 16 | 'Parser' 17 | ); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/util/test/addr.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const expect = chai.expect; 3 | 4 | const addr = require('../lib/addr'); 5 | 6 | describe('addr', () => { 7 | describe('from', () => { 8 | it('should return the hash and version', () => { 9 | let result = addr.from('17fm4xevwDh3XRHv9UoqYrVgPMbwcGHsUs'); 10 | console.log(result); 11 | expect(result).to.have.all.keys('version', 'hash'); 12 | }); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /packages/plugin/README.md: -------------------------------------------------------------------------------- 1 | # `@keyring/plugin` 2 | 3 | Base functionality for Keyring plugins and classes hosting plugins 4 | 5 | ## Usage 6 | 7 | ``` 8 | const Plugin = require('@keyring/plugin'); 9 | 10 | // For a class that is hosting plugins 11 | class Transaction extends Plugin.Host { 12 | ... 13 | } 14 | 15 | // For a class that is implementing plugin functionality 16 | class MsgpackPlugin extends Plugin.Provider { 17 | ... 18 | } 19 | ``` 20 | -------------------------------------------------------------------------------- /testall.sh: -------------------------------------------------------------------------------- 1 | 2 | test() { 3 | echo packages/${1}/ 4 | cd packages/${1}/ 5 | # npm i 6 | npm run test 7 | cd ../.. 8 | } 9 | 10 | # filelist=(bsv cbor-plugin chain keyring msgpack-plugin \ 11 | # plugin transaction txo-plugin util validation-plugin) 12 | List=( 13 | cbor-plugin 14 | chain 15 | msgpack-plugin 16 | plugin 17 | transaction 18 | txo-plugin 19 | util 20 | validation-plugin 21 | ) 22 | 23 | for Item in ${List[*]} ; 24 | do 25 | test $Item 26 | done 27 | 28 | echo done! `date` 29 | -------------------------------------------------------------------------------- /packages/util/lib/addr.js: -------------------------------------------------------------------------------- 1 | const Buf = require('./buf'); 2 | const bs58 = require('bs58check'); 3 | 4 | const Addr = { 5 | from(addr) { 6 | let buf = Buf.from(addr); 7 | let version = buf.slice(0,1); 8 | let hash = buf.slice(1); 9 | return {version, hash}; 10 | }, 11 | format(hash, version=0x00) { 12 | let _version = Buffer.alloc(1); 13 | _version.writeUInt8(version); 14 | 15 | return bs58.encode(Buffer.concat([_version, Buf.from(hash)])); 16 | } 17 | 18 | }; 19 | 20 | module.exports = Addr; 21 | -------------------------------------------------------------------------------- /packages/cbor-plugin/README.md: -------------------------------------------------------------------------------- 1 | # `@keyring/cbor-plugin` 2 | 3 | This plugin allows you to easily insert CBOR encoded data into a transaction. When using this plugin a cbor method is added to the Keyring Transaction class. 4 | 5 | ## Usage 6 | 7 | ``` 8 | const BSV = require('@keyring/bsv'); 9 | const cborPlugin = require('@keyring/cbor-plugin'); 10 | 11 | const Transaction = BSV.Transaction; 12 | Transaction.use(new cborPlugin()); 13 | 14 | let tx = new Transaction(); 15 | tx.cbor({ hello: 'world' }); 16 | console.log('data', tx.data()[0]); 17 | ``` 18 | 19 | -------------------------------------------------------------------------------- /packages/msgpack-plugin/README.md: -------------------------------------------------------------------------------- 1 | # `@keyring/msgpack-plugin` 2 | 3 | This plugin allows you to easily insert msgpack encoded data into a transaction. When using this plugin a msgpack method is added to the Keyring Transaction class. 4 | 5 | ## Usage 6 | 7 | ``` 8 | const BSV = require('@keyring/bsv'); 9 | const msgPackPlugin = require('@keyring/msgpack-plugin'); 10 | 11 | const Transaction = BSV.Transaction; 12 | Transaction.use(new msgPackPlugin()); 13 | 14 | let tx = new Transaction(); 15 | tx.msgpack({ hello: 'world' }); 16 | console.log('data', tx.data()[0]); 17 | ``` 18 | -------------------------------------------------------------------------------- /packages/txo-plugin/lib/index.js: -------------------------------------------------------------------------------- 1 | const Plugin = require('@keyring/plugin'); 2 | const TransactionFacet = require('./transaction'); 3 | 4 | const Package = require('../package.json'); 5 | 6 | class TXOPlugin extends Plugin.Provider { 7 | static get id() { return 'txo'; } 8 | static get name() { return 'TXO Plugin'; } 9 | static get description() { return Package.description; } 10 | static get version() { return Package.version; } 11 | 12 | static get facets() { 13 | return { transaction: TransactionFacet }; 14 | } 15 | } 16 | 17 | module.exports = TXOPlugin; 18 | 19 | -------------------------------------------------------------------------------- /packages/cbor-plugin/lib/index.js: -------------------------------------------------------------------------------- 1 | const Plugin = require('@keyring/plugin'); 2 | const TransactionFacet = require('./transaction'); 3 | 4 | const Package = require('../package.json'); 5 | 6 | class CBORPlugin extends Plugin.Provider { 7 | static get id() { return 'cbor'; } 8 | static get name() { return 'CBOR Plugin'; } 9 | static get description() { return Package.description; } 10 | static get version() { return Package.version; } 11 | 12 | static get facets() { 13 | return { transaction: TransactionFacet }; 14 | } 15 | } 16 | 17 | module.exports = CBORPlugin; 18 | 19 | -------------------------------------------------------------------------------- /packages/msgpack-plugin/lib/index.js: -------------------------------------------------------------------------------- 1 | const Plugin = require('@keyring/plugin'); 2 | const TransactionFacet = require('./transaction'); 3 | 4 | const Package = require('../package.json'); 5 | 6 | class MsgpackPlugin extends Plugin.Provider { 7 | static get id() { return 'msgpack'; } 8 | static get name() { return 'MsgPack Plugin'; } 9 | static get description() { return Package.description; } 10 | static get version() { return Package.version; } 11 | 12 | static get facets() { 13 | return { transaction: TransactionFacet }; 14 | } 15 | } 16 | 17 | module.exports = MsgpackPlugin; 18 | 19 | -------------------------------------------------------------------------------- /packages/chain/test/index.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const expect = chai.expect; 3 | 4 | const Chain = require('..'); 5 | const TemplateCollection = require('../lib/template-collection'); 6 | 7 | const Templates = require('./fixtures/templates'); 8 | 9 | describe('@keyring/chain', () => { 10 | describe('#instance', () => { 11 | it('should have create template collection', () => { 12 | let chain = new Chain({templates: Templates}); 13 | // console.log('chain >>', chain); 14 | expect(chain.templates).to.be.instanceof(TemplateCollection); 15 | }); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /packages/validation-plugin/lib/index.js: -------------------------------------------------------------------------------- 1 | const Plugin = require('@keyring/plugin'); 2 | const TransactionFacet = require('./transaction'); 3 | 4 | const Package = require('../package.json'); 5 | 6 | class ValidationPlugin extends Plugin.Provider { 7 | static get id() { return 'validation'; } 8 | static get name() { return 'Validation Plugin'; } 9 | static get description() { return Package.description; } 10 | static get version() { return Package.version; } 11 | 12 | static get facets() { 13 | return { transaction: TransactionFacet }; 14 | } 15 | } 16 | 17 | module.exports = ValidationPlugin; 18 | -------------------------------------------------------------------------------- /packages/util/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@keyring/util", 3 | "version": "0.2.0", 4 | "description": "Keyring util package", 5 | "main": "lib/index.js", 6 | "repository": "git@github.com:BitbossIO/keyring.git", 7 | "license": "MIT", 8 | "private": false, 9 | "scripts": { 10 | "test": "npx mocha", 11 | "test:watch": "npx mocha --watch" 12 | }, 13 | "devDependencies": { 14 | "chai": "^4.2.0", 15 | "mocha": "^5.2.0" 16 | }, 17 | "dependencies": { 18 | "bn.js": "^4.11.8", 19 | "bs58check": "^2.1.2", 20 | "ramda": "^0.26.1" 21 | }, 22 | "gitHead": "87c6e9b97dcce546d3633371c78bace73adab4a2" 23 | } 24 | -------------------------------------------------------------------------------- /packages/plugin/lib/host.js: -------------------------------------------------------------------------------- 1 | const _ = require('@keyring/util'); 2 | 3 | class Host { 4 | constructor(facet='default') { 5 | let plugins = this.constructor.plugins; 6 | for (let id of Object.keys(plugins)) { 7 | plugins[id].construct(facet, this); 8 | } 9 | } 10 | 11 | static use(provider, refresh) { 12 | throw new Error('method needs to be added to class'); 13 | } 14 | 15 | static _use(provider, facet, refresh=false) { 16 | if(refresh || !this.plugins[provider.id]) { 17 | this.plugins[provider.id] = provider; 18 | provider.init(facet, this); 19 | } 20 | } 21 | } 22 | 23 | Host.plugins = {}; 24 | 25 | module.exports = Host; 26 | -------------------------------------------------------------------------------- /packages/chain/lib/index.js: -------------------------------------------------------------------------------- 1 | const OpcodeCollection = require('./opcode-collection'); 2 | const TemplateCollection = require('./template-collection'); 3 | 4 | const Standard = { 5 | opcodes: require('./standard-opcodes'), 6 | templates: require('./standard-templates') 7 | }; 8 | 9 | class Chain { 10 | static get Standard() { return Standard; } 11 | 12 | constructor(config={}) { 13 | this.config = Object.assign(config, Standard); 14 | 15 | this.dataMode = config.dataMode || 'data'; 16 | this.opcodes = new OpcodeCollection(config.opcodes); 17 | this.templates = new TemplateCollection(this, config.templates); 18 | } 19 | } 20 | 21 | module.exports = Chain; 22 | 23 | -------------------------------------------------------------------------------- /packages/txo-plugin/README.md: -------------------------------------------------------------------------------- 1 | # `@keyring/txo-plugin` 2 | 3 | This plugin adds TXO conversion capabilities to the Keyring Transaction class. Using the plugin allows you to easily transform the raw transaction data into a JSON structured format to then use within Planaria for powerful queries and filters. 4 | 5 | ## Usage 6 | 7 | ``` 8 | const BSV = require('@keyring/bsv'); 9 | const TXOPlugin = require('@keyring/txo-plugin'); 10 | 11 | const Transaction = BSV.Transaction; 12 | Transaction.use(new TXOPlugin()); 13 | 14 | let tx = new Transaction([raw hex format as a string]); 15 | let txo = tx.txo(); 16 | // Do something with the txo JSON data such as inserting into a mongodb for querying capabilities 17 | ``` 18 | -------------------------------------------------------------------------------- /packages/chain/test/fixtures/templates.js: -------------------------------------------------------------------------------- 1 | const OP_RETURN = [0x6a]; 2 | const Data = [0x01,0x4c]; 3 | const Signature = [0x47, 0x48, 0x49]; 4 | const Pubkey = [0x21, 0x41]; 5 | 6 | const Templates = [ 7 | { 8 | id: 'data', 9 | patterns: [ 10 | [OP_RETURN, Data], 11 | [OP_RETURN, Data, Data], 12 | [OP_RETURN, Data, Data, Data], 13 | [OP_RETURN, Data, Data, Data, Data], 14 | [OP_RETURN, Data, Data, Data, Data, Data] 15 | ], 16 | data(script) {}, 17 | init(...data) {} 18 | }, { 19 | id: 'signature', 20 | pattern: 'signature pubkey', 21 | patterns: [ 22 | [Signature, Pubkey] 23 | ], 24 | data(script) {}, 25 | init(key, sighash, type, compressed=true) {} 26 | } 27 | ]; 28 | 29 | module.exports = Templates; 30 | -------------------------------------------------------------------------------- /packages/util/test/bn.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const expect = chai.expect; 3 | 4 | const BN = require('../lib/bn'); 5 | 6 | describe('bn', () => { 7 | describe('from', () => { 8 | it('should return BN of number', () => { 9 | let result = BN.from(10).eq(new BN(10)); 10 | expect(result).to.be.true; 11 | }); 12 | }); 13 | 14 | describe('constants', () => { 15 | it('should define One', () => { 16 | let result = BN.One.eq(new BN(1)); 17 | expect(result).to.be.true; 18 | }); 19 | 20 | it('should define Byte', () => { 21 | let result = BN.Byte.eq(new BN(1)); 22 | expect(result).to.be.true; 23 | }); 24 | 25 | it('should define KB', () => { 26 | let result = BN.KB.eq(new BN(1024)); 27 | expect(result).to.be.true; 28 | }); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /packages/chain/test/fixtures/opcodes.js: -------------------------------------------------------------------------------- 1 | const _ = require('@keyring/util'); 2 | 3 | const Next = (handler) => { 4 | return (op) => { return op._reader[handler](); }; 5 | }; 6 | 7 | const NextOpcodeBytes = (op) => { return op.code; }; 8 | 9 | const PushDataLen = (handler) => { 10 | return (op) => { return (new _.Writer())[handler](op.take).buf; }; 11 | }; 12 | 13 | const Opcodes = new Array(256); 14 | 15 | Opcodes[0x6a] = { identifier: 'OP_RETURN' }; 16 | 17 | Opcodes[0x4c] = { 18 | identifier: 'OP_PUSHDATA1', 19 | take: Next('uint8'), // bytes 20 | extra: PushDataLen('uint8'), 21 | group: '' 22 | } 23 | 24 | _.r.forEach((code) => { 25 | Opcodes[code] = { 26 | take: NextOpcodeBytes, 27 | identifier: 'Data', 28 | group: '' 29 | }; 30 | }, _.r.range(0x01, 0x4c)); 31 | 32 | module.exports = Opcodes; 33 | -------------------------------------------------------------------------------- /packages/util/lib/format.js: -------------------------------------------------------------------------------- 1 | const R = require('ramda'); 2 | const bs58 = require('bs58check'); 3 | 4 | const Format = { 5 | isHex(str) { return !R.isNil(str.match(/^([0-9a-fA-F]{2})+$/)); }, 6 | isBase58(str) { 7 | if (!str.length) { return false; } 8 | else if (!R.isNil(/^([1-9A-HJ-NP-Za-km-z])+$/)) { 9 | if(!R.isNil(bs58.decodeUnsafe(str))) { return true; } 10 | } 11 | return false; 12 | }, 13 | detect(any) { 14 | if (R.is(Array, any)) { return 'array'; } 15 | else if(R.is(Buffer, any)) { return 'buf'; } 16 | else if(R.is(String, any)) { 17 | if (!any.length) { return 'null'; } 18 | else if(this.isHex(any)) { return 'hex'; } 19 | else if(this.isBase58(any)) { return 'bs58'; } 20 | else { return 'string'; } 21 | } 22 | else { return 'unknown'; } 23 | } 24 | }; 25 | 26 | module.exports = Format; 27 | -------------------------------------------------------------------------------- /packages/bsv/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@keyring/bsv", 3 | "version": "0.2.2", 4 | "description": "Library for working with BSV", 5 | "author": "BitBoss", 6 | "homepage": "https://github.com/BitbossIO/keyring#readme", 7 | "license": "MIT", 8 | "main": "lib/index.js", 9 | "directories": { 10 | "lib": "lib", 11 | "test": "__tests__" 12 | }, 13 | "files": [ 14 | "lib" 15 | ], 16 | "publishConfig": { 17 | "access": "public" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/BitbossIO/keyring.git" 22 | }, 23 | "scripts": {}, 24 | "bugs": { 25 | "url": "https://github.com/BitbossIO/keyring/issues" 26 | }, 27 | "dependencies": { 28 | "@keyring/chain": "^0.2.0", 29 | "@keyring/transaction": "^0.2.2" 30 | }, 31 | "gitHead": "87c6e9b97dcce546d3633371c78bace73adab4a2" 32 | } 33 | -------------------------------------------------------------------------------- /packages/txo-plugin/test/index.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const expect = chai.expect; 3 | 4 | const Plugin = require('@keyring/plugin'); 5 | const TXOPlugin = require('../lib'); 6 | const Transaction = require('@keyring/transaction'); 7 | 8 | const vectors = require('./vectors.json'); 9 | 10 | describe('@keyring/txo-plugin', () => { 11 | describe('init', () => { 12 | it('should add .txo to transaction', () => { 13 | Transaction.use(new TXOPlugin()); 14 | let tx = new Transaction(); 15 | expect(typeof tx.txo).to.equal('function'); 16 | }); 17 | }); 18 | 19 | describe('txo', () => { 20 | it('should serialize a raw tx into the txo format', () => { 21 | Transaction.use(new TXOPlugin(), true); 22 | let tx = new Transaction(vectors[0].raw); 23 | let txo = tx.txo(); 24 | expect(txo).to.eql(vectors[0].txo); 25 | }); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /packages/chain/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@keyring/chain", 3 | "version": "0.2.0", 4 | "description": "Base chain for configuring keyring", 5 | "author": "BitBoss", 6 | "homepage": "https://github.com/BitbossIO/keyring#readme", 7 | "license": "MIT", 8 | "main": "lib/index.js", 9 | "directories": { 10 | "lib": "lib", 11 | "test": "test" 12 | }, 13 | "files": [ 14 | "lib" 15 | ], 16 | "publishConfig": {}, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/BitbossIO/keyring.git" 20 | }, 21 | "scripts": { 22 | "test": "mocha", 23 | "test:watch": "mocha --watch" 24 | }, 25 | "bugs": { 26 | "url": "https://github.com/BitbossIO/keyring/issues" 27 | }, 28 | "devDependencies": { 29 | "chai": "^4.2.0", 30 | "mocha": "^6.1.4" 31 | }, 32 | "dependencies": { 33 | "@keyring/util": "^0.2.0", 34 | "ramda": "^0.26.1" 35 | }, 36 | "gitHead": "87c6e9b97dcce546d3633371c78bace73adab4a2" 37 | } 38 | -------------------------------------------------------------------------------- /packages/plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@keyring/plugin", 3 | "version": "0.2.0", 4 | "description": "> TODO: description", 5 | "author": "BitBoss", 6 | "homepage": "https://github.com/BitbossIO/keyring#readme", 7 | "license": "MIT", 8 | "main": "lib/index.js", 9 | "directories": { 10 | "lib": "lib", 11 | "test": "test" 12 | }, 13 | "files": [ 14 | "lib" 15 | ], 16 | "publishConfig": { 17 | "access": "public" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/BitbossIO/keyring.git" 22 | }, 23 | "scripts": { 24 | "test": "npx mocha", 25 | "test:watch": "npx mocha --watch" 26 | }, 27 | "bugs": { 28 | "url": "https://github.com/BitbossIO/keyring/issues" 29 | }, 30 | "devDependencies": { 31 | "chai": "^4.2.0", 32 | "mocha": "^6.1.4" 33 | }, 34 | "dependencies": { 35 | "@keyring/util": "^0.2.0" 36 | }, 37 | "gitHead": "87c6e9b97dcce546d3633371c78bace73adab4a2" 38 | } 39 | -------------------------------------------------------------------------------- /packages/keyring/README.md: -------------------------------------------------------------------------------- 1 | # Keyring 2 | 3 | ***Warning*** - This library is new and changing rapidly. 4 | 5 | Keyring is a collection of javascript libraries for working with Bitcoin(BSV) transactions and wallets. 6 | 7 | ## Libraries 8 | 9 | [BSV](https://github.com/BitbossIO/keyring/tree/master/packages/bsv) - The BSV library loads the most commonly needed modules to get you started working with the BSV chain. 10 | 11 | [Transaction](https://github.com/BitbossIO/keyring/tree/master/packages/transaction) - The Transaction library handles transaction parsing, creation, signing, and more. 12 | 13 | [Util](https://github.com/BitbossIO/keyring/tree/master/packages/util) - The Util package contains helpers shared by the other libraries. 14 | 15 | ## Contributing 16 | 17 | All contributions of code, feedback, and feature requests are welcome. We will be using github issues to track work and will monitor it closely. Right now keyring is bare bones, but we have a nice base to build the dev tools bitcoin needs. 18 | -------------------------------------------------------------------------------- /packages/util/lib/buf.js: -------------------------------------------------------------------------------- 1 | const R = require('ramda'); 2 | const bs58 = require('bs58check'); 3 | const Format = require('./format'); 4 | 5 | const Buf = { 6 | from(buf) { 7 | if(typeof buf == 'object' && !R.isNil(buf.buf)) { buf = buf.buf; } 8 | if(typeof buf == 'function') { buf = buf(); } 9 | 10 | let type = Format.detect(buf); 11 | 12 | if(type === 'hex') { buf = Buffer.from(buf, 'hex'); } 13 | else if(type === 'bs58') { buf = bs58.decode(buf); } 14 | else if(type === 'null') { buf = Buffer.alloc(0); } 15 | else if(type === 'array') { buf = Buffer.concat(R.map(this.from, buf)); } 16 | else if(!R.is(Buffer, buf)) { throw new TypeError('invalid buffer'); } 17 | return buf; 18 | }, 19 | bytes(buf) { return R.splitEvery(1, this.from(buf)); }, 20 | reverse(buf) { 21 | buf = this.from(buf); 22 | return this.bytes(buf).reduce((acc, val, index) => { 23 | acc[acc.length-1-index] = val[0]; 24 | return acc; 25 | }, Buffer.alloc(buf.length)); 26 | } 27 | }; 28 | 29 | module.exports = Buf; 30 | -------------------------------------------------------------------------------- /packages/txo-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@keyring/txo-plugin", 3 | "version": "0.2.1", 4 | "description": "> TODO: description", 5 | "author": "BitBoss", 6 | "homepage": "https://github.com/BitbossIO/keyring#readme", 7 | "license": "MIT", 8 | "main": "lib/index.js", 9 | "directories": { 10 | "lib": "lib", 11 | "test": "test" 12 | }, 13 | "files": [ 14 | "lib" 15 | ], 16 | "publishConfig": { 17 | "access": "public" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/BitbossIO/keyring.git" 22 | }, 23 | "scripts": { 24 | "test": "npx mocha", 25 | "test:watch": "npx mocha --watch" 26 | }, 27 | "bugs": { 28 | "url": "https://github.com/BitbossIO/keyring/issues" 29 | }, 30 | "dependencies": { 31 | "@keyring/plugin": "^0.2.0", 32 | "@keyring/util": "^0.2.0" 33 | }, 34 | "devDependencies": { 35 | "@keyring/transaction": "^0.2.1", 36 | "chai": "^4.2.0", 37 | "mocha": "^6.1.4" 38 | }, 39 | "gitHead": "87c6e9b97dcce546d3633371c78bace73adab4a2" 40 | } 41 | -------------------------------------------------------------------------------- /packages/validation-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@keyring/validation-plugin", 3 | "version": "0.2.1", 4 | "description": "> TODO: description", 5 | "author": "BitBoss", 6 | "homepage": "https://github.com/BitbossIO/keyring#readme", 7 | "license": "MIT", 8 | "main": "lib/index.js", 9 | "directories": { 10 | "lib": "lib", 11 | "test": "test" 12 | }, 13 | "files": [ 14 | "lib" 15 | ], 16 | "publishConfig": { 17 | "access": "public" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/BitbossIO/keyring.git" 22 | }, 23 | "scripts": { 24 | "test": "npx mocha", 25 | "test:watch": "npx mocha --watch" 26 | }, 27 | "bugs": { 28 | "url": "https://github.com/BitbossIO/keyring/issues" 29 | }, 30 | "dependencies": { 31 | "@keyring/plugin": "^0.2.0", 32 | "@keyring/util": "^0.2.0" 33 | }, 34 | "devDependencies": { 35 | "@keyring/transaction": "^0.2.1", 36 | "chai": "^4.2.0", 37 | "mocha": "^6.1.4" 38 | }, 39 | "gitHead": "87c6e9b97dcce546d3633371c78bace73adab4a2" 40 | } 41 | -------------------------------------------------------------------------------- /packages/plugin/lib/provider.js: -------------------------------------------------------------------------------- 1 | class Provider { 2 | static get id() { return 'noid'; } 3 | static get name() { return 'unnamed'; } 4 | static get description() { return 'none'; } 5 | static get version() { return 'none'; } 6 | 7 | static get facets() { return {}; } 8 | 9 | constructor(options={}) { 10 | let facetClasses = this.constructor.facets; 11 | 12 | this.options = options; 13 | this.facets = {}; 14 | 15 | for (let facet of Object.keys(facetClasses)) { 16 | this.facets[facet] = new (facetClasses[facet])(this, options); 17 | } 18 | } 19 | 20 | get id() { return this.constructor.id; } 21 | get name() { return this.constructor.name; } 22 | get description() { return this.constructor.description; } 23 | get version() { return this.constructor.version; } 24 | 25 | init(facet, hostClass) { 26 | facet = this.facets[facet]; 27 | if (facet) { facet.init(hostClass); } 28 | } 29 | 30 | construct(facet, hostInstance) { 31 | facet = this.facets[facet]; 32 | if (facet) { facet.construct(hostInstance); } 33 | } 34 | } 35 | 36 | module.exports = Provider; 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 BitBoss 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/cbor-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@keyring/cbor-plugin", 3 | "version": "0.2.1", 4 | "description": "Plugin for storing data in a transaction with cbor encoding", 5 | "author": "BitBoss", 6 | "homepage": "https://github.com/BitbossIO/keyring#readme", 7 | "license": "MIT", 8 | "main": "lib/index.js", 9 | "directories": { 10 | "lib": "lib", 11 | "test": "test" 12 | }, 13 | "files": [ 14 | "lib" 15 | ], 16 | "publishConfig": { 17 | "access": "public" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/BitbossIO/keyring.git" 22 | }, 23 | "scripts": { 24 | "test": "npx mocha", 25 | "test:watch": "npx mocha --watch" 26 | }, 27 | "bugs": { 28 | "url": "https://github.com/BitbossIO/keyring/issues" 29 | }, 30 | "dependencies": { 31 | "@keyring/plugin": "^0.2.0", 32 | "@keyring/util": "^0.2.0", 33 | "borc": "^2.1.0" 34 | }, 35 | "devDependencies": { 36 | "@keyring/transaction": "^0.2.1", 37 | "chai": "^4.2.0", 38 | "mocha": "^6.1.4" 39 | }, 40 | "gitHead": "87c6e9b97dcce546d3633371c78bace73adab4a2" 41 | } 42 | -------------------------------------------------------------------------------- /packages/transaction/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@keyring/transaction", 3 | "version": "0.2.2", 4 | "description": "Keyring transaction package", 5 | "author": "BitBoss", 6 | "homepage": "https://github.com/BitbossIO/keyring#readme", 7 | "license": "MIT", 8 | "main": "lib/index.js", 9 | "directories": { 10 | "lib": "lib", 11 | "test": "test" 12 | }, 13 | "files": [ 14 | "lib" 15 | ], 16 | "publishConfig": { 17 | "access": "public" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/BitbossIO/keyring.git" 22 | }, 23 | "scripts": { 24 | "test": "npx mocha", 25 | "test:watch": "npx mocha --watch" 26 | }, 27 | "bugs": { 28 | "url": "https://github.com/BitbossIO/keyring/issues" 29 | }, 30 | "devDependencies": { 31 | "chai": "^4.2.0", 32 | "chai-bignumber": "^3.0.0", 33 | "mocha": "^5.2.0" 34 | }, 35 | "dependencies": { 36 | "@keyring/chain": "^0.2.0", 37 | "@keyring/plugin": "^0.2.0", 38 | "@keyring/util": "^0.2.0", 39 | "ecc-tools": "^1.0.14" 40 | }, 41 | "gitHead": "87c6e9b97dcce546d3633371c78bace73adab4a2" 42 | } 43 | -------------------------------------------------------------------------------- /packages/msgpack-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@keyring/msgpack-plugin", 3 | "version": "0.2.1", 4 | "description": "Plugin for storing data in a transaction with msgpack encoding", 5 | "author": "BitBoss", 6 | "homepage": "https://github.com/BitbossIO/keyring#readme", 7 | "license": "MIT", 8 | "main": "lib/index.js", 9 | "directories": { 10 | "lib": "lib", 11 | "test": "test" 12 | }, 13 | "files": [ 14 | "lib" 15 | ], 16 | "publishConfig": { 17 | "access": "public" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/BitbossIO/keyring.git" 22 | }, 23 | "scripts": { 24 | "test": "npx mocha", 25 | "test:watch": "npx mocha --watch" 26 | }, 27 | "bugs": { 28 | "url": "https://github.com/BitbossIO/keyring/issues" 29 | }, 30 | "dependencies": { 31 | "@keyring/plugin": "^0.2.0", 32 | "@keyring/util": "^0.2.0", 33 | "@msgpack/msgpack": "^1.1.2" 34 | }, 35 | "devDependencies": { 36 | "@keyring/transaction": "^0.2.1", 37 | "chai": "^4.2.0", 38 | "mocha": "^6.1.4" 39 | }, 40 | "gitHead": "87c6e9b97dcce546d3633371c78bace73adab4a2" 41 | } 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | .DS_Store 63 | /.scannerwork/ -------------------------------------------------------------------------------- /packages/cbor-plugin/lib/transaction.js: -------------------------------------------------------------------------------- 1 | const _ = require('@keyring/util'); 2 | const cbor = require('borc'); 3 | 4 | const DefaultOptions = { 5 | transaction: {} 6 | }; 7 | 8 | class TransactionFacet { 9 | constructor(root, options={}) { 10 | this.root = root; 11 | this.options = Object.assign({}, DefaultOptions, options); 12 | } 13 | 14 | init(klass) {} 15 | 16 | construct(tx) { 17 | const plugin = this; 18 | 19 | tx.cbor = (data) => { 20 | if(_.r.isNil(data)) { 21 | let results = []; 22 | tx.data().forEach((datum) => { 23 | if( 24 | datum 25 | && datum[0].toString() === '19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut' 26 | && datum[2].toString() == 'application/cbor' 27 | ) { 28 | try { 29 | results.push(cbor.decode(datum[1])); 30 | } catch (err) {} 31 | } 32 | }); 33 | return results; 34 | } else { 35 | return tx.data( 36 | '19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut', 37 | cbor.encode(data), 38 | 'application/cbor', 39 | 'binary' 40 | ); 41 | } 42 | }; 43 | } 44 | } 45 | 46 | module.exports = TransactionFacet; 47 | -------------------------------------------------------------------------------- /packages/cbor-plugin/test/index.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const expect = chai.expect; 3 | 4 | const CBORPlugin = require('../lib'); 5 | const Transaction = require('@keyring/transaction'); 6 | 7 | const cbor = require('borc'); 8 | 9 | 10 | describe('@keyring/cbor-plugin', () => { 11 | describe('init', () => { 12 | it('should add .cbor to transaction', () => { 13 | Transaction.use(new CBORPlugin()); 14 | let tx = new Transaction(); 15 | expect(typeof tx.cbor).to.equal('function'); 16 | }); 17 | }); 18 | 19 | describe('cbor', () => { 20 | it('should add cbor encoded data', () => { 21 | Transaction.use(new CBORPlugin(), true); 22 | let tx = new Transaction(); 23 | tx.cbor({hello: 'world'}); 24 | 25 | expect(cbor.decode(tx.data()[0][1])).to.eql({hello: 'world'}); 26 | }); 27 | 28 | it('should read cbor encoded data', () => { 29 | Transaction.use(new CBORPlugin(), true); 30 | let tx = new Transaction(); 31 | tx.data(Buffer.from('deadbeef', 'hex')); 32 | tx.cbor({hello: 'world'}); 33 | 34 | expect(tx.data().length).to.equal(2); 35 | expect(tx.cbor().length).to.equal(1); 36 | expect(tx.cbor()[0]).to.eql({hello: 'world'}); 37 | }); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /packages/msgpack-plugin/lib/transaction.js: -------------------------------------------------------------------------------- 1 | const _ = require('@keyring/util'); 2 | const msgpack = require('@msgpack/msgpack'); 3 | 4 | const DefaultOptions = { 5 | transaction: {} 6 | }; 7 | 8 | class TransactionFacet { 9 | constructor(root, options={}) { 10 | this.root = root; 11 | this.options = Object.assign({}, DefaultOptions, options); 12 | } 13 | 14 | init(klass) {} 15 | 16 | construct(tx) { 17 | const plugin = this; 18 | 19 | tx.msgpack = (data) => { 20 | if(_.r.isNil(data)) { 21 | let results = []; 22 | tx.data().forEach((datum) => { 23 | if( 24 | datum 25 | && datum[0].toString() === '19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut' 26 | && datum[2].toString() == 'application/msgpack' 27 | ) { 28 | try { 29 | results.push(msgpack.decode(datum[1])); 30 | } catch (err) {} 31 | } 32 | }); 33 | return results; 34 | } else { 35 | return tx.data( 36 | '19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut', 37 | Buffer.from(msgpack.encode(data)), 38 | 'application/msgpack', 39 | 'binary' 40 | ); 41 | } 42 | }; 43 | } 44 | } 45 | 46 | module.exports = TransactionFacet; 47 | -------------------------------------------------------------------------------- /packages/util/lib/parser.js: -------------------------------------------------------------------------------- 1 | const R = require('ramda'); 2 | 3 | const Reader = require('./reader'); 4 | 5 | class Parser { 6 | constructor(template) { this.template = template; } 7 | 8 | parse(buf) { return this._parse(new Reader(buf), this.template); } 9 | 10 | _parse(reader, template, index) { 11 | let klass; 12 | 13 | if (R.is(Function, template)) { 14 | klass = template; 15 | template = template.template; 16 | template = R.is(Function, template) ? template() : template; 17 | } 18 | 19 | let result = R.reduce((result, item) => { 20 | let [key, val] = item; 21 | if (!R.isNil(index)) { result['_index'] = index; } 22 | if (R.is(Function, val)) { 23 | result[key] = this._parse(reader, val); 24 | } else if (R.is(Array, val)) { 25 | val = val.length === 1 && R.is(Function, val[0]) ? val[0] : val; 26 | result[key] = R.times((i) => { 27 | return this._parse(reader, val, i); 28 | }, reader.varint().toNumber()); 29 | } else { 30 | let [type, ...args] = val.split(':'); 31 | result[key] = reader[type](...args); 32 | } 33 | return result; 34 | }, {}, (template)); 35 | return klass ? new klass(result) : result; 36 | } 37 | }; 38 | 39 | module.exports = Parser; 40 | -------------------------------------------------------------------------------- /packages/msgpack-plugin/test/index.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const expect = chai.expect; 3 | 4 | const MsgpackPlugin = require('../lib'); 5 | const Transaction = require('@keyring/transaction'); 6 | 7 | const msgpack = require('@msgpack/msgpack'); 8 | 9 | 10 | describe('@keyring/msgpack-plugin', () => { 11 | describe('init', () => { 12 | it('should add .msgpack to transaction', () => { 13 | Transaction.use(new MsgpackPlugin()); 14 | let tx = new Transaction(); 15 | expect(typeof tx.msgpack).to.equal('function'); 16 | }); 17 | }); 18 | 19 | describe('msgpack', () => { 20 | it('should add msgpack encoded data', () => { 21 | Transaction.use(new MsgpackPlugin(), true); 22 | let tx = new Transaction(); 23 | tx.msgpack({hello: 'world'}); 24 | 25 | expect(msgpack.decode(tx.data()[0][1])).to.eql({hello: 'world'}); 26 | }); 27 | 28 | it('should read msgpack encoded data', () => { 29 | Transaction.use(new MsgpackPlugin(), true); 30 | let tx = new Transaction(); 31 | tx.data(Buffer.from('deadbeef', 'hex')); 32 | tx.msgpack({hello: 'world'}); 33 | 34 | expect(tx.data().length).to.equal(2); 35 | expect(tx.msgpack().length).to.equal(1); 36 | expect(tx.msgpack()[0]).to.eql({hello: 'world'}); 37 | }); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /packages/validation-plugin/README.md: -------------------------------------------------------------------------------- 1 | # `@keyring/validation-plugin` 2 | 3 | This plugin allows a developer to easily verify a transaction before sending it off to a node. When using this plugin a validate method is added to the Keyring Transaction class. By default it checks for the following: 4 | * The transaction has inputs 5 | * The transaction inputs are signed 6 | * The transaction outputs are over the dust amount 7 | * The transaction has a fee 8 | 9 | 10 | ## Usage 11 | 12 | ``` 13 | const BSV = require('@keyring/bsv'); 14 | const validationPlugin = require('@keyring/validation-plugin'); 15 | 16 | let options = { 17 | transaction: { 18 | hasInputs: true, 19 | inputsAreSigned: true, 20 | outputsAreOver: 500, 21 | hasFee: true 22 | } 23 | }; 24 | 25 | const Transaction = BSV.Transaction; 26 | Transaction.use(new validationPlugin(options)); 27 | 28 | let tx = new Transaction().from( 29 | { 30 | txid: '729b4706357b70c6aae58cd556e895d9441a7741aeb9436419ecaf18e764ea41', 31 | index: 2, 32 | asm: 'OP_DUP OP_HASH160 108748bafaa372bcaa21b1858eccc78b54fcd371 OP_EQUALVERIFY OP_CHECKSIG', 33 | amount: 1638569 34 | } 35 | ); 36 | 37 | tx.validate(); 38 | if (tx.errors.length > 0) { 39 | console.log('Validation errors exist', tx.errors); 40 | } 41 | ``` 42 | 43 | ## Example output 44 | 45 | ``` 46 | Validation errors exist [ { index: 0, 47 | key: 'inputsAreSigned', 48 | message: 'Input 0 is not signed.' } ] 49 | ``` 50 | -------------------------------------------------------------------------------- /packages/util/lib/reader.js: -------------------------------------------------------------------------------- 1 | const R = require('ramda'); 2 | const BN = require('bn.js'); 3 | 4 | const _ = { buf: require('./buf') }; 5 | 6 | class Reader { 7 | constructor(_buf='') { 8 | if(R.is(Reader, _buf)) { return _buf; } 9 | this._buf = _.buf.from(_buf); 10 | this._pos = 0; 11 | return this; 12 | } 13 | 14 | get buf() { return this._buf; } 15 | get hex() { return this._buf.toString('hex'); } 16 | get eof() { return this._pos >= this._buf.length; } 17 | 18 | read(len, handler='slice') { 19 | len = parseInt(len); 20 | let buf = this._buf[handler](this._pos, this._pos + len); 21 | this._pos += len; 22 | return buf; 23 | } 24 | 25 | reverse(len) { return _.buf.reverse(this.read(parseInt(len))); } 26 | 27 | compact() { 28 | let buf = this.read(1); 29 | if (buf[0] <= 252) { return buf; } 30 | else { return this.read(Math.pow(2, (buf[0] - 252))); } 31 | } 32 | 33 | varint() { return new BN(_.buf.reverse(this.compact()).toString('hex'), 16); } 34 | 35 | vardata() { return this.read(this.varint().toNumber()); } 36 | 37 | uint8() { return this.read(1, 'readUInt8'); } 38 | 39 | uint16le() { return this.read(2, 'readUInt16LE'); } 40 | uint16be() { return this.read(2, 'readUInt16BE'); } 41 | 42 | uint32le() { return this.read(4, 'readUInt32LE'); } 43 | uint32be() { return this.read(4, 'readUInt32BE'); } 44 | 45 | uint64le() { return new BN(this.reverse(8).toString('hex'), 16); } 46 | uint64be() { return new BN(this.read(8).toString('hex'), 16); } 47 | }; 48 | 49 | module.exports = Reader; 50 | -------------------------------------------------------------------------------- /packages/transaction/test/input.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const expect = chai.expect; 3 | 4 | const Input = require('../lib/input'); 5 | const Script = require('../lib/script'); 6 | 7 | const txid = 'aaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee'; 8 | const txid_reverse = 'eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa'; 9 | const txout = '00000000'; 10 | const script = '483045022100c41c6d5cec0e8ee920a860729cbaf5c23811e0c1132d60261df9db846717553102205b8fa81b93fa16095383200c2f8acb52947e05aec1c5853f919bdece62d9ca9a012102378c1377c8fa2f3cfb9ddc235d8d336a354d7522a323489e0bcd8fdbd8651483'; 11 | const seq = 'ffffffff'; 12 | 13 | const inhex = txid_reverse + txout + (script.length / 2).toString(16) + script + seq; 14 | const noscript = txid_reverse + txout + '00' + seq; 15 | 16 | describe('Input', () => { 17 | describe('#instance', () => { 18 | it('should return a Script instance', () => { 19 | let input = new Input(); 20 | expect(input).to.be.an.instanceof(Input); 21 | }); 22 | 23 | it('should parse a buffer', () => { 24 | let output = new Input(Buffer.from(inhex, 'hex')); 25 | expect(output.txid.toString('hex')).to.equal(txid); 26 | expect(output.index).to.equal(0); 27 | expect(output.script).to.be.an.instanceof(Script); 28 | expect(output.sequence).to.equal(0xffffffff); 29 | }); 30 | }); 31 | 32 | describe('buf', () => { 33 | it('should return the buffer for the input', () => { 34 | let input = new Input(inhex); 35 | expect(input.buf.toString('hex')).to.eql(inhex); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /packages/chain/test/opcode.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const expect = chai.expect; 3 | 4 | const _ = require('@keyring/util'); 5 | 6 | const OpcodeCollection = require('../lib/opcode-collection'); 7 | const Opcode = require('../lib/opcode'); 8 | 9 | const opcodes = new OpcodeCollection(require('./fixtures/opcodes')); 10 | 11 | describe('Opcode', () => { 12 | describe('#instance', () => { 13 | it('should return an Opcode instance', () => { 14 | let opcode = new Opcode(opcodes, ''); 15 | expect(opcode).to.be.an.instanceof(Opcode); 16 | }); 17 | 18 | it('should take a reader and read the next op', () => { 19 | let opcode = new Opcode(opcodes, '01deadbeef'); 20 | expect(opcode.code).is.equal(0x01); 21 | expect(opcode.data.toString('hex')).is.equal('de'); 22 | expect(opcode._reader._pos).is.equal(2); 23 | 24 | }); 25 | 26 | it('should set the identifier', () => { 27 | let opcode = new Opcode(opcodes, '6a'); 28 | expect(opcode.code).is.equal(0x6a); 29 | expect(opcode.identifier).is.equal('OP_RETURN'); 30 | }); 31 | 32 | it('should set the identifier to the data if Data', () => { 33 | let opcode = new Opcode(opcodes, new _.Reader('04deadbeef')); 34 | expect(opcode.code).is.equal(0x04); 35 | expect(opcode.data.toString('hex')).is.equal('deadbeef'); 36 | expect(opcode.identifier).is.equal('deadbeef'); 37 | }); 38 | 39 | it('should set extra', () => { 40 | let opcode = new Opcode(opcodes, new _.Reader('4c04deadbeef')); 41 | expect(opcode.code).is.equal(0x4c); 42 | expect(opcode.extra[0]).is.equal(0x04); 43 | expect(opcode.data.toString('hex')).is.equal('deadbeef'); 44 | expect(opcode.identifier).is.equal('deadbeef'); 45 | }); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /packages/util/test/format.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const expect = chai.expect; 3 | 4 | const Format = require('../lib/format'); 5 | 6 | describe('format', () => { 7 | describe('isHex', () => { 8 | it('should return true for hex', () => { 9 | let result = Format.isHex('deadbeef'); 10 | expect(result).to.be.true; 11 | }); 12 | 13 | it('should return false for empty string', () => { 14 | let result = Format.isHex(''); 15 | expect(result).to.be.false; 16 | }); 17 | 18 | it('should return false for bs58', () => { 19 | let result = Format.isHex('17fm4xevwDh3XRHv9UoqYrVgPMbwcGHsUs'); 20 | expect(result).to.be.false; 21 | }); 22 | }); 23 | 24 | describe('isBase58', () => { 25 | it('should return false for hex', () => { 26 | let result = Format.isBase58('deadbeef'); 27 | expect(result).to.be.false; 28 | }); 29 | 30 | it('should return false for empty string', () => { 31 | let result = Format.isBase58(''); 32 | expect(result).to.be.false; 33 | }); 34 | 35 | it('should return true for bs58', () => { 36 | let result = Format.isBase58('17fm4xevwDh3XRHv9UoqYrVgPMbwcGHsUs'); 37 | expect(result).to.be.true; 38 | }); 39 | }); 40 | 41 | describe('detect', () => { 42 | it('should return hex for hex', () => { 43 | let result = Format.detect('deadbeef'); 44 | expect(result).to.equal('hex'); 45 | }); 46 | 47 | it('should return empty for empty string', () => { 48 | let result = Format.detect(''); 49 | expect(result).to.equal('null'); 50 | }); 51 | 52 | it('should return bs58 for bs58', () => { 53 | let result = Format.detect('17fm4xevwDh3XRHv9UoqYrVgPMbwcGHsUs'); 54 | expect(result).to.equal('bs58'); 55 | }); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /packages/chain/lib/opcode-collection.js: -------------------------------------------------------------------------------- 1 | const _ = require('@keyring/util'); 2 | 3 | const Opcode = require('./opcode'); 4 | 5 | class OpcodeCollection extends Array { 6 | constructor(opcodes=[]) { 7 | super(...opcodes); 8 | 9 | opcodes.forEach((meta, code) => { 10 | let buf = Buffer.alloc(1); 11 | buf.writeUInt8(code); 12 | meta.buf = buf; 13 | meta.code = code; 14 | 15 | let identifiers = meta.identifiers || []; 16 | if(meta.identifier) { identifiers.push(meta.identifier); } 17 | identifiers.forEach((identifier) => { 18 | this[identifier] = this[identifier] || []; 19 | this[identifier].push(code); 20 | }); 21 | }); 22 | } 23 | 24 | get(identifier) { 25 | if(_.r.is(String, identifier)) { 26 | return _.r.map((id) => { 27 | return this[id]; 28 | }, (this[identifier] || [])); 29 | } else { return [this[identifier]]; } 30 | } 31 | 32 | next(reader) { 33 | if (_.r.is(String, reader)) { return new Opcode(new _.Reader(reader)); } 34 | return new Opcode(this, reader); 35 | } 36 | 37 | fromRaw(raw) { 38 | let opcodes = []; 39 | let reader = new _.Reader(raw); 40 | 41 | while (!reader.eof) { 42 | opcodes.push(this.next(reader)); 43 | } 44 | 45 | return opcodes; 46 | } 47 | 48 | fromASM(asm) { 49 | return _.r.map((val) => { 50 | let code = this.get(val)[0]; 51 | if (_.r.isNil(code)) { 52 | return Opcode.fromData(this, val); 53 | } else { 54 | return new Opcode(this, new (_.Reader)(code.buf)); 55 | } 56 | }, asm.split(' ')); 57 | } 58 | 59 | fromData(...data) { 60 | return _.r.map((datum) => { 61 | return Opcode.fromData(this, datum); 62 | }, data); 63 | } 64 | } 65 | 66 | module.exports = OpcodeCollection; 67 | -------------------------------------------------------------------------------- /packages/transaction/test/output.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const expect = chai.expect; 3 | 4 | const Output = require('../lib/output'); 5 | 6 | const p2pkhm_spkq = '76a91459288e0ec97813bab904867cdcae0d681f6cce5188ac1c73706b71ca325ab67a8f1decb61546a8950da859a08601000000000075'; 7 | const p2pkhm_spkg = '76a9146872715a6aeaab180807322b8dc6c0bef7d4419f88ac0c73706b6700e1f5050000000075'; 8 | 9 | describe('Output', () => { 10 | describe('#instance', () => { 11 | it('should return a Script instance', () => { 12 | let output = new Output(); 13 | expect(output).to.be.an.instanceof(Output); 14 | }); 15 | 16 | it('should parse a buffer', () => { 17 | let output = new Output(Buffer.from(p2pkhm_spkq, 'hex')); 18 | expect(output.amount.toString()).to.equal('14487673355241826678'); 19 | }); 20 | }); 21 | 22 | describe('meta', () => { 23 | it('should return assets for a p2pkhm with spkq metadata', () => { 24 | let output = new Output({amount: 0, script: p2pkhm_spkq}); 25 | expect(output.meta.id).to.equal('spkq'); 26 | expect(output.meta.assets).to.eql({'59a80d95a84615b6ec1d8f7ab65a32ca': 100000}); 27 | }); 28 | 29 | it('should return assets for a p2pkhm with spkg metadata', () => { 30 | let output = new Output({amount: 10, script: p2pkhm_spkg}); 31 | expect(output.meta.id).to.equal('spkg'); 32 | expect(output.meta.type).to.equal('mc-issuance-quantity'); 33 | expect(output.meta.quantity.toString(10)).to.equal('100000000'); 34 | }); 35 | }); 36 | 37 | describe('buf', () => { 38 | it('should return the buffer for the output', () => { 39 | let output = new Output({amount: 10, script: p2pkhm_spkq}); 40 | expect(output.buf.toString('hex')).to.eql('0a0000000000000037' + p2pkhm_spkq); 41 | }); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /packages/transaction/lib/output.js: -------------------------------------------------------------------------------- 1 | const _ = require('@keyring/util'); 2 | 3 | const Script = require('./script'); 4 | 5 | class Output { 6 | get chain() { return this.constructor.chain; } 7 | static get chain() { return { Script }; } 8 | 9 | constructor(raw='') { 10 | if (_.r.is(Output, raw)) { raw = raw.buf; } 11 | if (_.r.is(Buffer, raw) || typeof raw === 'string') { 12 | return new _.Parser(this.constructor).parse(raw); 13 | } 14 | 15 | this.raw = raw; 16 | this.tx = raw.tx || {}; 17 | this.index = raw._index || raw.index; 18 | this.amount = new (_.bn)(raw.amount || 0); 19 | 20 | if (_.r.isNil(raw.script) && _.r.is(String, raw.asm)) { 21 | this.script = new Script('asm', raw.asm); 22 | } else { this.script = new Script(raw.script || ''); } 23 | 24 | return this; 25 | } 26 | 27 | get meta() { return this.script.meta; } 28 | get data() { return this.script.data; } 29 | get destination() { return this.script.destination; } 30 | 31 | get buf() { 32 | return new _.Writer() 33 | .uint64le(this.amount) 34 | .vardata(this.script.buf) 35 | .buf; 36 | } 37 | 38 | get hex() { return this.buf.toString('hex'); } 39 | get txid() { return this.raw.txid || this.tx.id; } 40 | 41 | clone(output={}) { return new (this.constructor)(Object.assign(this.raw, output)); } 42 | 43 | blank() { 44 | this.amount = new (_.bn)('ffffffffffffffff', 16); 45 | this.script.set('blank'); 46 | } 47 | 48 | static template() { 49 | return [ 50 | ['amount', 'uint64le'], 51 | ['script', 'vardata'] 52 | ]; 53 | } 54 | 55 | static for(chain) { 56 | chain.Script = chain.Script || Script.for(chain); 57 | 58 | class OutputClass extends Output { 59 | static get chain() { return chain; } 60 | } 61 | 62 | return OutputClass; 63 | } 64 | } 65 | 66 | module.exports = Output; 67 | -------------------------------------------------------------------------------- /packages/chain/test/template-collection.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const expect = chai.expect; 3 | 4 | const TemplateCollection = require('../lib/template-collection'); 5 | 6 | const Templates = require('../lib/standard-templates'); 7 | const Chain = require('../lib/index'); 8 | const chain = new Chain({templates: []}); 9 | 10 | describe('template-collection', () => { 11 | describe('#instance', () => { 12 | it('should extend array', () => { 13 | let tpls = new TemplateCollection(chain, Templates); 14 | expect(tpls).to.be.instanceof(Array); 15 | }); 16 | 17 | it('should add templates to instance', () => { 18 | let tpls = new TemplateCollection(chain, Templates); 19 | expect(tpls.length).to.equal(6); 20 | }); 21 | }); 22 | 23 | describe('index generation', () => { 24 | it('should build an index', () => { 25 | let tpls = new TemplateCollection(chain, Templates); 26 | 27 | expect(tpls.find([{code: 0x6a}])).to.be.undefined; 28 | expect(tpls.find([{code: 0x6a}, {code: 0x01}]).id).to.equal('data'); 29 | expect(tpls.find([{code: 0x47}, {code: 0x21}]).id).to.equal('signature'); 30 | }); 31 | }); 32 | 33 | describe('find', () => { 34 | it('should find p2pkhm', () => { 35 | let opcodes =[ 36 | { code: 118 }, 37 | { code: 169 }, 38 | { code: 20 }, 39 | { code: 136 }, 40 | { code: 172 }, 41 | { code: 28 }, 42 | { code: 117 } 43 | ]; 44 | 45 | let tpls = new TemplateCollection(chain, Templates); 46 | 47 | expect(tpls.find(opcodes).id).to.equal('p2pkhm'); 48 | }); 49 | 50 | it('should find p2pkhm', () => { 51 | let opcodes =[ 52 | { code: 0x6a }, 53 | { code: 0x14 }, 54 | { code: 0x14 } 55 | ]; 56 | 57 | let tpls = new TemplateCollection(chain, Templates); 58 | 59 | expect(tpls.find(opcodes).id).to.equal('data'); 60 | }); 61 | 62 | }); 63 | 64 | }); 65 | -------------------------------------------------------------------------------- /packages/util/lib/writer.js: -------------------------------------------------------------------------------- 1 | const R = require('ramda'); 2 | const BN = require('bn.js'); 3 | 4 | const _ = { buf: require('./buf') }; 5 | 6 | class Writer { 7 | constructor(_buf='') { 8 | if(R.is(Writer, _buf)) { return _buf; } 9 | this._buf = _.buf.from(_buf); 10 | return this; 11 | } 12 | 13 | get buf() { return this._buf; } 14 | get hex() { return this._buf.toString('hex'); } 15 | 16 | write(buf) { 17 | if(R.is(Array, buf)) { this.varint(buf.length).write(_.buf.from(buf)); } 18 | else { this._buf = Buffer.concat([this._buf, _.buf.from(buf)]); } 19 | return this; 20 | } 21 | 22 | reverse(buf) { 23 | this.write(_.buf.reverse(buf)); 24 | return this; 25 | } 26 | 27 | vardata(buf) { 28 | buf = _.buf.from(buf); 29 | return this.varint(buf.length).write(buf); 30 | } 31 | 32 | varint(int) { 33 | int = new BN(int); 34 | if(int.gte(new BN(0)) && int.lte(new BN(252))) { this.uint8(int); } 35 | else if(int.gte(new BN(253)) && int.lte(new BN('ffff', 16))) { this.uint8(253).uint16le(int); } 36 | else if(int.gte(new BN('10000', 16)) && int.lte(new BN('ffffffff', 16))) { this.uint8(254).uint32le(int); } 37 | else if(int.gte(new BN('100000000', 16)) && int.lte(new BN('ffffffffffffffff', 16))) { this.uint8(255).uint64le(int); } 38 | return this; 39 | } 40 | 41 | uint8(int) { return this.write((new BN(int)).toArrayLike(Buffer, 'le', 1)); } 42 | 43 | uint16le(int) { return this.write((new BN(int)).toArrayLike(Buffer, 'le', 2)); } 44 | uint16be(int) { return this.write((new BN(int)).toArrayLike(Buffer, 'be', 2)); } 45 | 46 | uint32le(int) { return this.write((new BN(int)).toArrayLike(Buffer, 'le', 4)); } 47 | uint32be(int) { return this.write((new BN(int)).toArrayLike(Buffer, 'be', 4)); } 48 | 49 | uint64le(int) { return this.write((new BN(int)).toArrayLike(Buffer, 'le', 8)); } 50 | uint64be(int) { return this.write((new BN(int)).toArrayLike(Buffer, 'be', 8)); } 51 | }; 52 | 53 | module.exports = Writer; 54 | -------------------------------------------------------------------------------- /packages/transaction/lib/script.js: -------------------------------------------------------------------------------- 1 | const _ = require('@keyring/util'); 2 | const Chain = require('@keyring/chain'); 3 | 4 | const StandardChain = new Chain(); 5 | 6 | class Script { 7 | get chain() { return this.constructor.chain; } 8 | static get chain() { return StandardChain; } 9 | 10 | constructor(raw='', ...args) { 11 | if(raw instanceof Script) { return raw; } 12 | return this.set(raw, ...args); 13 | } 14 | 15 | set(raw, ...args) { 16 | this._pos = 0; 17 | this.stack = []; 18 | this.raw = raw = this.chain.templates.init(raw, ...args); 19 | 20 | if (raw === 'asm') { this.opcodes = this.chain.opcodes.fromASM(...args); } 21 | else { this.opcodes = this.chain.opcodes.fromRaw(raw); } 22 | 23 | return this; 24 | } 25 | 26 | get buf() { return Buffer.concat(_.r.pluck('buf', this.opcodes)); } 27 | get hex() { return this.buf.toString('hex'); } 28 | get asm() { return _.r.pluck('identifier', this.opcodes).join(' '); } 29 | 30 | get template() { 31 | return this.chain.templates.find(this.opcodes); 32 | } 33 | 34 | get fingerprint() { return _.r.pluck('label', this.opcodes).join(' '); } 35 | 36 | get _meta() { return this.template.meta; } 37 | get meta() { return _.r.is(Function, this._meta) ? this._meta(this) : {}; } 38 | 39 | get _data() { return this.template.data; } 40 | get data() { return _.r.is(Function, this._data) ? this._data(this) : false; } 41 | 42 | get _source() { return this.template.source; } 43 | get source() { return _.r.is(Function, this._source) ? this._source(this) : []; } 44 | 45 | get _destination() { return this.template.destination; } 46 | get destination() { return _.r.is(Function, this._destination) ? this._destination(this) : []; } 47 | 48 | static for(chain) { 49 | class ScriptClass extends Script { 50 | static get chain() { return chain; } 51 | } 52 | 53 | return ScriptClass; 54 | } 55 | } 56 | 57 | Script.empty = () => { return new Script(); }; 58 | 59 | module.exports = Script; 60 | -------------------------------------------------------------------------------- /packages/chain/lib/template-collection.js: -------------------------------------------------------------------------------- 1 | const _ = require('@keyring/util'); 2 | 3 | class TemplateCollection extends Array { 4 | constructor(chain, templates=[], index) { 5 | super(...templates); 6 | this.chain = chain; 7 | this._index = index; 8 | this._indexed = 0; 9 | 10 | if(!this._index) { 11 | this._index = []; 12 | this.index(); 13 | } 14 | } 15 | 16 | _addFilter(filter, key, pos=0) { 17 | if(!this._index[pos]) { this._index[pos] = new Array(256); } 18 | let current = this._index[pos][key] || 0b00; 19 | this._index[pos][key] = current | filter; 20 | } 21 | 22 | index(start=this._indexed, len=this.length-start) { 23 | this._indexed = start + len; 24 | for(let i=start; i { 29 | pattern = pattern.split(' '); 30 | this._addFilter(filter, pattern.length); 31 | pattern.forEach((ops, pos) => { 32 | ops = this.chain.opcodes.get(ops); 33 | ops.forEach((op) => { 34 | this._addFilter(filter, op.code, pos + 1); 35 | }); 36 | }); 37 | }); 38 | } 39 | return this._index; 40 | } 41 | 42 | init(idx, ...args) { 43 | let tpl = this[idx]; 44 | if(tpl && tpl.init && _.r.is(Function, tpl.init)) { 45 | return tpl.init.apply(this, args); 46 | } else { return idx; } 47 | } 48 | 49 | _find(opcodes, index=this._index) { 50 | if(opcodes.opcodes) { opcodes = opcodes.opcodes; } 51 | 52 | let matches = opcodes.reduce((acc, op, idx) => { 53 | return acc & this._index[idx + 1][op.code]; 54 | }, this._index[0][opcodes.length] || 0b00); 55 | 56 | if(matches === 0) { return false; } 57 | return Math.floor(Math.log2(matches)); 58 | } 59 | 60 | find(opcodes, index) { 61 | return this[this._find(opcodes, index)]; 62 | } 63 | } 64 | 65 | module.exports = TemplateCollection; 66 | -------------------------------------------------------------------------------- /packages/chain/lib/opcode.js: -------------------------------------------------------------------------------- 1 | const _ = require('@keyring/util'); 2 | 3 | class Opcode { 4 | constructor(opcodes=[], reader) { 5 | if (_.r.is(String, reader)) { return new Opcode(opcodes, new _.Reader(reader)); } 6 | 7 | this._reader = reader; 8 | 9 | this.buf = reader.read(1); 10 | this.code = this.buf[0]; 11 | this.op = opcodes[this.code] || { identifier: 'UNKNOWN_OP' }; 12 | this.take = _.r.is(Function, this.op.take) ? this.op.take(this) : this.op.take; 13 | 14 | if (this.take) { this.data = reader.read(this.take); } 15 | if(_.r.is(Function, this.op.extra)) { this.extra = this.op.extra(this); } 16 | 17 | if(this.extra) { this.buf = Buffer.concat([this.buf, this.extra]); }; 18 | if(this.data) { this.buf = Buffer.concat([this.buf, this.data]); } 19 | 20 | this.group = this.op.group; 21 | this.label = this.group || this.identifier; 22 | 23 | return this; 24 | } 25 | 26 | get identifier() { 27 | return ( 28 | this.data || 29 | this.op.identifier || 30 | '0x' + this.code 31 | ).toString('hex'); 32 | } 33 | 34 | static fromData(opcodes, data) { 35 | data = _.buf.from(data); 36 | 37 | let buf; 38 | if (data.length >= 0x01 && data.length <= 0x4c) { 39 | buf = Buffer.alloc(1); 40 | buf.writeUInt8(data.length); 41 | } else if (data.length > 0x4c && data.length <= 0xff) { 42 | buf = Buffer.alloc(2); 43 | buf.writeUInt8(0x4c); 44 | buf.writeUInt8(data.length, 1); 45 | } else if (data.length > 0x4c && data.length <= 0xff) { 46 | buf = Buffer.alloc(3); 47 | buf.writeUInt8(0x4d); 48 | buf.writeUInt16LE(data.length, 1); 49 | } else if (data.length > 0xff && data.length <= 0xffffffff) { 50 | buf = Buffer.alloc(5); 51 | buf.writeUInt8(0x4e); 52 | buf.writeUInt32LE(data.length, 1); 53 | } else { throw new Error('data too big, how did you even do that?'); } 54 | 55 | return new Opcode(opcodes, new _.Reader(Buffer.concat([buf, data]))); 56 | } 57 | } 58 | 59 | module.exports = Opcode; 60 | -------------------------------------------------------------------------------- /packages/chain/test/opcode-collection.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const expect = chai.expect; 3 | const _ = require('@keyring/util'); 4 | 5 | const OpcodeCollection = require('../lib/opcode-collection'); 6 | const Opcode = require('../lib/opcode'); 7 | 8 | const Opcodes = require('./fixtures/opcodes'); 9 | 10 | describe('OpcodeCollection', () => { 11 | describe('#instance', () => { 12 | it('should extend array', () => { 13 | let opcodes = new OpcodeCollection(); 14 | expect(opcodes).to.be.instanceof(Array); 15 | }); 16 | 17 | it('should add Opcodes to instance', () => { 18 | let opcodes = new OpcodeCollection(Opcodes); 19 | expect(opcodes.length).to.equal(256); 20 | }); 21 | 22 | it('should add identifiers', () => { 23 | let opcodes = new OpcodeCollection(Opcodes); 24 | expect(opcodes.OP_RETURN[0]).to.equal(0x6a); 25 | }); 26 | }); 27 | 28 | describe('get', () => { 29 | it('should return an array of opcode details', () => { 30 | let opcodes = new OpcodeCollection(Opcodes); 31 | let result = opcodes.get('OP_RETURN'); 32 | expect(result.length).to.equal(1); 33 | expect(result[0].code).to.equal(0x6a); 34 | }); 35 | }); 36 | 37 | describe('next', () => { 38 | it('should return an opcode instance', () => { 39 | let opcodes = new OpcodeCollection(Opcodes); 40 | let result = opcodes.next(new _.Reader('6a')); 41 | expect(result).to.be.an.instanceof(Opcode); 42 | }); 43 | }); 44 | 45 | describe('fromRaw', () => { 46 | it('should return an array of opcode instances', () => { 47 | let opcodes = new OpcodeCollection(Opcodes); 48 | let result = opcodes.fromRaw('6a02dead'); 49 | expect(result[0]).to.be.an.instanceof(Opcode); 50 | }); 51 | }); 52 | 53 | describe('fromASM', () => { 54 | it('should return an array of opcode instances', () => { 55 | let opcodes = new OpcodeCollection(Opcodes); 56 | let result = opcodes.fromASM('OP_RETURN dead'); 57 | // console.log('results >>>', result); 58 | expect(result[0]).to.be.an.instanceof(Opcode); 59 | }); 60 | }); 61 | 62 | }); 63 | -------------------------------------------------------------------------------- /packages/util/test/parser.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const expect = chai.expect; 3 | 4 | const Parser = require('../lib/parser'); 5 | 6 | class Note { constructor(raw) { this.raw = raw; } } 7 | 8 | Note.template = [ 9 | ['version', 'uint8'], 10 | ['message', 'vardata'] 11 | ]; 12 | 13 | describe('Parser', () => { 14 | describe('#instance', () => { 15 | it('should return a Parser instance', () => { 16 | let parser = new Parser('deadbeef'); 17 | expect(parser).to.be.instanceof(Parser); 18 | }); 19 | }); 20 | 21 | describe('parse', () => { 22 | it('should accept a buffer and parse it using the template', () => { 23 | let parser = new Parser([['version', 'uint8'], ['msg', 'vardata']]); 24 | let result = parser.parse('0304deadbeef'); 25 | expect(result.version).to.equal(3); 26 | expect(result.msg.toString('hex')).to.equal('deadbeef'); 27 | }); 28 | 29 | it('should recursively handle arrays in a template', () => { 30 | let parser = new Parser([['version', 'uint8'], ['msg','uint8'], ['notes', [['body', 'uint8']]]]); 31 | let result = parser.parse('0304020506'); 32 | expect(result).to.eql({ 33 | version: 3, 34 | msg: 4, 35 | notes: [{_index: 0, body: 5}, {_index: 1, body: 6}] 36 | }); 37 | }); 38 | 39 | it('should create instances for constructors with a template attribute', () => { 40 | let parser = new Parser(Note); 41 | let result = parser.parse('0304deadbeef'); 42 | expect(result).to.be.instanceof(Note); 43 | expect(result.raw.message.toString('hex')).to.equal('deadbeef'); 44 | }); 45 | 46 | it('should create a single instance', () => { 47 | let parser = new Parser([['note', Note]]); 48 | let result = parser.parse('010304deadbeef'); 49 | expect(result.note).to.be.instanceof(Note); 50 | }); 51 | 52 | it('should create an array of instances', () => { 53 | let parser = new Parser([['notes', [Note]]]); 54 | let result = parser.parse('010304deadbeef'); 55 | expect(result.notes).to.be.instanceof(Array); 56 | expect(result.notes[0]).to.be.instanceof(Note); 57 | }); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /packages/transaction/test/sighash.js: -------------------------------------------------------------------------------- 1 | const _ = require('@keyring/util'); 2 | 3 | const chai = require('chai'); 4 | const expect = chai.expect; 5 | 6 | const Sighash = require('../lib/sighash'); 7 | const Transaction = require('../lib'); 8 | 9 | const MidstateVectors = require('./vectors/midstates.json'); 10 | const SighashVectors = require('./vectors/unhashed.json'); 11 | 12 | 13 | describe('Sighash', () => { 14 | describe('#instance', () => { 15 | it('should return a Sighash instance', () => { 16 | let tx = new Transaction(SighashVectors[0][0]); 17 | let sighash = new Sighash(tx); 18 | expect(sighash).to.be.instanceof(Sighash); 19 | }); 20 | }); 21 | 22 | // describe('midstates', () => { 23 | // _.r.addIndex(_.r.forEach)((vector, i) => { 24 | // let tx = new Transaction(vector[0]); 25 | // let sighash = new Sighash(tx); 26 | 27 | // it(`should calculate prevout hash for vector ${i}`, () => { 28 | // expect(sighash.prevouts.toString('hex')).to.equal(vector[2]); 29 | // }); 30 | 31 | // it(`should calculate sequence hash for vector ${i}`, () => { 32 | // expect(sighash.sequence.toString('hex')).to.equal(vector[3]); 33 | // }); 34 | 35 | // it(`should calculate outputs hash for vector ${i}`, () => { 36 | // expect(sighash.outputs.toString('hex')).to.equal(vector[4]); 37 | // }); 38 | 39 | // it(`should calculate per input prevout hash for vector ${i}`, () => { 40 | // expect(sighash.prevouts.toString('hex')).to.equal(vector[2]); 41 | // }); 42 | // }, MidstateVectors); 43 | // }); 44 | 45 | // describe('hash', () => { 46 | // _.r.addIndex(_.r.forEach)((vector, i) => { 47 | // let tx = new Transaction(vector[0]); 48 | // let sighash = new Sighash(tx); 49 | 50 | // it(`should calculate the sighash for vector ${i}`, () => { 51 | // let hash = sighash.hash(vector[2], vector[1], 0, (vector[3] >>> 0)); 52 | // let unhash = sighash._original(vector[2], vector[1], 0, (vector[3] >>> 0)); 53 | // expect(_.buf.reverse(hash).toString('hex')).to.equal(vector[4]); 54 | // }); 55 | // }, SighashVectors); 56 | // }); 57 | }); 58 | -------------------------------------------------------------------------------- /packages/chain/lib/standard-opcodes.js: -------------------------------------------------------------------------------- 1 | const _ = require('@keyring/util'); 2 | 3 | const Next = (handler) => { 4 | return (op) => { return op._reader[handler](); }; 5 | }; 6 | 7 | const NextOpcodeBytes = (op) => { return op.code; }; 8 | 9 | const PushDataLen = (handler) => { 10 | return (op) => { return (new _.Writer())[handler](op.take).buf; }; 11 | }; 12 | 13 | const StandardOpcodes = new Array(256); 14 | 15 | StandardOpcodes[0x00] = { 16 | identifier: 'OP_FALSE', 17 | identifiers: ['OP_FALSE', 'OP_0'] 18 | }; 19 | 20 | StandardOpcodes[0x4c] = { 21 | identifier: 'OP_PUSHDATA1', 22 | identifiers: ['DATA'], 23 | take: Next('uint8'), // bytes 24 | extra: PushDataLen('uint8'), 25 | group: '' 26 | }; 27 | 28 | StandardOpcodes[0x4d] = { 29 | identifier: 'OP_PUSHDATA2', 30 | identifiers: ['DATA'], 31 | take: Next('uint16le'), // bytes 32 | extra: PushDataLen('uint16le'), 33 | group: '' 34 | }; 35 | 36 | StandardOpcodes[0x4e] = { 37 | identifier: 'OP_PUSHDATA4', 38 | identifiers: ['DATA'], 39 | take: Next('uint32le'), // bytes 40 | extra: PushDataLen('uint32le'), 41 | group: '' 42 | }; 43 | 44 | StandardOpcodes[0x51] = { 45 | identifier: 'OP_TRUE', 46 | identifiers: ['OP_TRUE', 'OP_1'] 47 | }; 48 | 49 | StandardOpcodes[0x6a] = { identifier: 'OP_RETURN' }; 50 | StandardOpcodes[0x75] = { identifier: 'OP_DROP' }; 51 | StandardOpcodes[0x76] = { identifier: 'OP_DUP' }; 52 | StandardOpcodes[0x88] = { identifier: 'OP_EQUALVERIFY' }; 53 | StandardOpcodes[0xa9] = { identifier: 'OP_HASH160' }; 54 | StandardOpcodes[0xac] = { identifier: 'OP_CHECKSIG' }; 55 | 56 | _.r.forEach((code) => { 57 | StandardOpcodes[code] = { 58 | take: NextOpcodeBytes, 59 | identifier: 'DATA', 60 | group: '' 61 | }; 62 | }, _.r.range(0x01, 0x4c)); 63 | 64 | _.r.forEach((code) => { 65 | StandardOpcodes[code].identifiers = ['SIGNATURE']; 66 | }, [0x47, 0x48, 0x49]); 67 | 68 | _.r.forEach((code) => { 69 | StandardOpcodes[code].identifiers = ['PUBKEY']; 70 | }, [0x21, 0x41]); 71 | 72 | _.r.forEach((code) => { 73 | StandardOpcodes[code] = { 74 | identifier: `OP_${code - 0x50}`, 75 | group: '[2-16]' 76 | }; 77 | }, _.r.range(0x52, 0x61)); 78 | 79 | module.exports = StandardOpcodes; 80 | -------------------------------------------------------------------------------- /packages/validation-plugin/lib/transaction.js: -------------------------------------------------------------------------------- 1 | const _ = require('@keyring/util'); 2 | 3 | const DefaultOptions = { 4 | transaction: { 5 | hasInputs: true, 6 | inputsAreSigned: true, 7 | outputsAreOver: 546, 8 | hasFee: true 9 | } 10 | }; 11 | 12 | class TransactionFacet { 13 | constructor(root, options={}) { 14 | this.root = root; 15 | this.options = Object.assign({}, DefaultOptions, options); 16 | } 17 | 18 | init(klass) {} 19 | 20 | construct(tx) { 21 | tx.errors = []; 22 | const plugin = this; 23 | 24 | tx.validate = (options={}) => { 25 | options = Object.assign({}, plugin.options.transaction, options); 26 | tx.errors = []; 27 | 28 | // Check that there are inputs 29 | if (options.hasInputs && !tx.inputs.length) { 30 | tx.errors.push({ 31 | key: 'hasInputs', 32 | message: 'Transaction must have at least one input.' 33 | }); 34 | } 35 | 36 | // Check that all inputs are signed 37 | if (options.inputsAreSigned) { 38 | tx.inputs.forEach((input, index) => { 39 | if (!input.script.template || input.script.template.id !== 'signature') { 40 | tx.errors.push({ 41 | index, 42 | key: 'inputsAreSigned', 43 | message: `Input ${index} is not signed.` 44 | }); 45 | } 46 | }); 47 | } 48 | 49 | // Check that all outputs are greater than dust (546 sats) 50 | if (options.outputsAreOver) { 51 | tx.outputs.forEach((output, index) => { 52 | if (output.amount.lte(_.bn.from(options.outputsAreOver))) { 53 | tx.errors.push({ 54 | index, 55 | key: 'outputsAreOver', 56 | message: `Output ${index} is below dust amount.` 57 | }); 58 | } 59 | }); 60 | } 61 | 62 | // Check that unspent amount > 0 63 | if (options.hasFee && !tx.unspent.gt(_.bn.Zero)) { 64 | tx.errors.push({ 65 | key: 'hasFee', 66 | message: 'Transaction must have a fee' 67 | }); 68 | } 69 | 70 | return !tx.errors.length; 71 | }; 72 | } 73 | } 74 | 75 | module.exports = TransactionFacet; 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Keyring 2 | 3 | ***Warning*** - This library is new and changing rapidly. 4 | 5 | Keyring is a collection of javascript libraries for working with Bitcoin(BSV) transactions and wallets. 6 | 7 | ## Libraries 8 | 9 | [BSV](https://github.com/BitbossIO/keyring/tree/master/packages/bsv) - The BSV library loads the most commonly needed modules to get you started working with the BSV chain. 10 | 11 | [Transaction](https://github.com/BitbossIO/keyring/tree/master/packages/transaction) - The Transaction library handles transaction parsing, creation, signing, and more. 12 | 13 | [Util](https://github.com/BitbossIO/keyring/tree/master/packages/util) - The Util package contains helpers shared by the other libraries. 14 | 15 | ## Plugins 16 | 17 | The Keyring library has several plugins and more will be added over time. Plugins provide convenient access to extra functionality that you can access directly from your Transaction class instance. Current plugins include: 18 | 19 | 20 | [Validation](https://github.com/BitbossIO/keyring/tree/master/packages/validation-plugin) - Adds a validate method to the Transaction instance to verify if the transaction is valid before sending it to a blockchain node. 21 | 22 | [CBOR](https://github.com/BitbossIO/keyring/tree/master/packages/cbor-plugin) - Adds a convenience method to insert CBOR encoded data into a transaction. 23 | 24 | [MsgPack](https://github.com/BitbossIO/keyring/tree/master/packages/msgpack-plugin) - Adds a convenience method to insert msgpack encoded data into a transaction. 25 | 26 | [TXO](https://github.com/BitbossIO/keyring/tree/master/packages/txo-plugin) - Adds TXO conversion capabilities to the Keyring Transaction class. 27 | 28 | All plugins are in the keyring/packages directory; each one ends in `-plugin`. There is example usage code in each plugin readme file. You simply require the plugin npm package separately and then register it using Transaction.use() before instantiating a new Transaction instance variable. 29 | 30 | 31 | ## Contributing 32 | 33 | All contributions of code, feedback, and feature requests are welcome. We will be using github issues to track work and will monitor it closely. Right now keyring is bare bones, but we have a nice base to build the dev tools bitcoin needs. 34 | -------------------------------------------------------------------------------- /packages/transaction/README.md: -------------------------------------------------------------------------------- 1 | # Keyring - Transaction 2 | 3 | @keyring/transaction is a javascript library for creating and signing bitcoin transactions, allowing you to easily build wallets for the Bitcoin SV blockchain. 4 | 5 | ### To add Keyring to your javascript project: 6 | ``` 7 | npm install @keyring/transaction —save 8 | ``` 9 | 10 | ### Reference the Transaction package 11 | Add a require reference at the top of your code. 12 | ``` 13 | const Transaction = require('@keyring/transaction'); 14 | ``` 15 | 16 | 17 | ### Instantiate a new Transaction object 18 | You can create a new transaction object by passing in the (string) hex representation of an existing blockchain transaction. 19 | ``` 20 | let txin = new Transaction(hexData); 21 | ``` 22 | 23 | Another option is to pass in an Output object into the Transaction.from() method. You can also pass an array of outputs into the Transaction.from method. The amount is specified in satoshi. 24 | ``` 25 | let tx = new Transaction().from( 26 | { 27 | txid: '729b4706357b70c6aae58cd556e895d9441a7741aeb9436419ecaf18e764ea41', 28 | index: 2, 29 | asm: 'OP_DUP OP_HASH160 108748bafaa372bcaa21b1858eccc78b54fcd371 OP_EQUALVERIFY OP_CHECKSIG', 30 | amount: 1638569 31 | } 32 | ); 33 | ``` 34 | 35 | ### Set the “to” address 36 | The address value should be in the standard address format, passed in as a string. Also include the amount of crypto being sent to that address. 37 | ``` 38 | tx.to(address, satoshis); 39 | ``` 40 | 41 | 42 | ### Set the fee 43 | By default the fee is auto calculated, but if you want to manually set it you can use the .fee(satoshis) method. If you want to ensure the default is used pass in 0. 44 | ``` 45 | tx.fee(10000); 46 | ``` 47 | 48 | ### Specify the change address 49 | The address value should be in the standard address format, passed in as a string. 50 | ``` 51 | tx.change(address); 52 | ``` 53 | 54 | ### Set OP_RETURN data 55 | Set data into an OP_RETURN as a node.js Buffer value. 56 | ``` 57 | tx.data(Buffer.from(myDataAsString)); 58 | ``` 59 | 60 | Note that you can also chain together Transaction method calls, for example: 61 | ``` 62 | tx.to(address, satoshis).change(address).data(Buffer.from(myDataAsString)); 63 | ``` 64 | 65 | 66 | ### Sign and Serialize the Transaction 67 | Sign with the private key as a node.js Buffer value, and then serialize the transaction. You can then broadcast it using a SPV server’s API. 68 | ``` 69 | tx.sign(privKey); 70 | const serializedTx = tx.hex; 71 | // send serializedTx... 72 | ``` 73 | -------------------------------------------------------------------------------- /packages/validation-plugin/test/index.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const expect = chai.expect; 3 | 4 | const ValidationPlugin = require('../lib'); 5 | const Transaction = require('@keyring/transaction'); 6 | 7 | const addr = '1KynqMpA5e5h3uy69fayPQkVVm9toePm4y'; 8 | 9 | const Enable = (key, value=true) => { 10 | let options = { 11 | transaction: { 12 | hasInputs: false, 13 | inputsAreSigned: false, 14 | outputsAreOver: 0, 15 | hasFee: false 16 | } 17 | }; 18 | options.transaction[key] = value; 19 | return options; 20 | }; 21 | 22 | describe('@keyring/validation-plugin', () => { 23 | describe('init', () => { 24 | it('should add .validate to transaction', () => { 25 | Transaction.use(new ValidationPlugin()); 26 | let tx = new Transaction(); 27 | expect(typeof tx.validate).to.equal('function'); 28 | }); 29 | 30 | it('should add .errors to transaction', () => { 31 | Transaction.use(new ValidationPlugin()); 32 | let tx = new Transaction(); 33 | expect(Array.isArray(tx.errors)).to.be.true; 34 | }); 35 | }); 36 | 37 | describe('validate', () => { 38 | it('should add error if options.hasInput and tx has no inputs', () => { 39 | Transaction.use(new ValidationPlugin(Enable('hasInputs')), true); 40 | let tx = new Transaction(); 41 | tx.validate(); 42 | expect(tx.errors.length).to.equal(1); 43 | expect(tx.errors[0].key).to.equal('hasInputs'); 44 | }); 45 | 46 | it('should add error if options.inputsAreSigned and inputs are not signed', () => { 47 | Transaction.use(new ValidationPlugin(Enable('inputsAreSigned')), true); 48 | let txin = new Transaction(); 49 | txin.to(addr, 1000).to(addr,2000); 50 | let tx = new Transaction(); 51 | tx.from(txin.outputs).validate(); 52 | expect(tx.errors.length).to.equal(2); 53 | expect(tx.errors[0].key).to.equal('inputsAreSigned'); 54 | }); 55 | 56 | it('should add error if options.outputsAreOver and outputs are lt', () => { 57 | Transaction.use(new ValidationPlugin(Enable('outputsAreOver', 600)), true); 58 | let tx = new Transaction(); 59 | tx.to(addr, 100).validate(); 60 | tx.to(addr, 1000).validate(); 61 | expect(tx.errors.length).to.equal(1); 62 | expect(tx.errors[0].key).to.equal('outputsAreOver'); 63 | }); 64 | 65 | it('should add error if options.hasFee and tx has no fee', () => { 66 | Transaction.use(new ValidationPlugin(Enable('hasFee')), true); 67 | let tx = new Transaction(); 68 | tx.validate(); 69 | expect(tx.errors.length).to.equal(1); 70 | expect(tx.errors[0].key).to.equal('hasFee'); 71 | }); 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /packages/txo-plugin/lib/transaction.js: -------------------------------------------------------------------------------- 1 | const _ = require('@keyring/util'); 2 | 3 | class TransactionFacet { 4 | constructor(root, options) { 5 | this.root = root; 6 | this.options = options; 7 | } 8 | 9 | init(klass) {} 10 | 11 | construct(tx) { 12 | tx.txo = () => { 13 | let inputs = []; 14 | let outputs = []; 15 | 16 | tx.inputs.forEach((input, index) => { 17 | if (input.script.raw.length) { 18 | let xput = { i: index }; 19 | input.script.opcodes.forEach((opcode, index) => { 20 | if (opcode.data) { 21 | if (opcode.data.length >= 512) { 22 | xput['lb' + index] = opcode.data.toString('base64'); 23 | } else { 24 | xput['b' + index] = opcode.data.toString('base64'); 25 | } 26 | } else { 27 | xput['b' +index] = { op: opcode.code[0] }; 28 | } 29 | }); 30 | xput.str = input.script.asm; 31 | let sender = { 32 | h: input.txid.toString('hex'), 33 | i: input.index 34 | }; 35 | 36 | let address = input.source[0]; 37 | if (address) { 38 | sender.a = _.addr.format(address); 39 | } 40 | 41 | xput.e = sender; 42 | inputs.push(xput); 43 | } 44 | }); 45 | 46 | tx.outputs.forEach((output, index) => { 47 | if (output.script.raw.length) { 48 | let xput = { i: index }; 49 | 50 | output.script.opcodes.forEach((opcode, index) => { 51 | if (opcode.data) { 52 | if (opcode.data.length >= 512) { 53 | xput['lb' + index] = opcode.data.toString('base64'); 54 | xput['ls' + index] = opcode.data.toString('utf8'); 55 | } else { 56 | xput['b' + index] = opcode.data.toString('base64'); 57 | xput['s' + index] = opcode.data.toString('utf8'); 58 | } 59 | } else { 60 | xput['b' +index] = { op: opcode.code }; 61 | } 62 | }); 63 | 64 | xput.str = output.script.asm; 65 | 66 | let receiver = { 67 | v: output.amount.toNumber(), 68 | i: index 69 | }; 70 | 71 | let address = output.destination[0]; 72 | if (address) { 73 | receiver.a = _.addr.format(address); 74 | } 75 | 76 | xput.e = receiver; 77 | outputs.push(xput); 78 | } 79 | }); 80 | 81 | return { 82 | tx: { h: tx.id.toString('hex') }, 83 | in: inputs, 84 | out: outputs 85 | }; 86 | }; 87 | } 88 | } 89 | 90 | module.exports = TransactionFacet; 91 | -------------------------------------------------------------------------------- /packages/txo-plugin/test/vectors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "raw": "0100000001d5001345e77e66fa74f0012a81017ea1223c7a8adbcc9e37f2860f95ba97966d000000006b483045022100c1a0c5ffc5b78e39acb5be1438e28a10e5aac8337f5da7e4c25ba4c5f3eb01b5022050e9997bae423585da52d7cdc8951379f5bff07adb6756ffe70e7c7181f8a5bd4121032b345f89620af75f59aa91d47cc359e4dd907816ce0652604922726025712f52ffffffff024a976200000000001976a914c6187747f80b85170eef7013218e7b0fa441479988ac44033f00000000001976a9147e4616b7453185a5f071417bb4ac08e226dbef9888ac00000000", 4 | "txo": { 5 | "tx": { 6 | "h": "3a737de7faa2ae1914f57ca0a11fd471334e40d4079d98cd77d27727e388b09d" 7 | }, 8 | "in": [ 9 | { 10 | "i": 0, 11 | "b0": "MEUCIQDBoMX/xbeOOay1vhQ44ooQ5arIM39dp+TCW6TF8+sBtQIgUOmZe65CNYXaUtfNyJUTefW/8HrbZ1b/5w58cYH4pb1B", 12 | "b1": "Ays0X4liCvdfWaqR1HzDWeTdkHgWzgZSYEkicmAlcS9S", 13 | "str": "3045022100c1a0c5ffc5b78e39acb5be1438e28a10e5aac8337f5da7e4c25ba4c5f3eb01b5022050e9997bae423585da52d7cdc8951379f5bff07adb6756ffe70e7c7181f8a5bd41 032b345f89620af75f59aa91d47cc359e4dd907816ce0652604922726025712f52", 14 | "e": { 15 | "h": "6d9697ba950f86f2379eccdb8a7a3c22a17e01812a01f074fa667ee7451300d5", 16 | "i": 0, 17 | "a": "1GbYyv2WxiMy7m1YDV76vWkCsfAZxpLqP4" 18 | } 19 | } 20 | ], 21 | "out": [ 22 | { 23 | "i": 0, 24 | "b0": { 25 | "op": 118 26 | }, 27 | "b1": { 28 | "op": 169 29 | }, 30 | "b2": "xhh3R/gLhRcO73ATIY57D6RBR5k=", 31 | "s2": "�\u0018wG�\u000b�\u0017\u000e�p\u0013!�{\u000f�AG�", 32 | "b3": { 33 | "op": 136 34 | }, 35 | "b4": { 36 | "op": 172 37 | }, 38 | "str": "OP_DUP OP_HASH160 c6187747f80b85170eef7013218e7b0fa4414799 OP_EQUALVERIFY OP_CHECKSIG", 39 | "e": { 40 | "v": 6461258, 41 | "i": 0, 42 | "a": "1K4S6uYLpx7yLZ1upgnfCQmBV3K2orkByu" 43 | } 44 | }, 45 | { 46 | "i": 1, 47 | "b0": { 48 | "op": 118 49 | }, 50 | "b1": { 51 | "op": 169 52 | }, 53 | "b2": "fkYWt0UxhaXwcUF7tKwI4ibb75g=", 54 | "s2": "~F\u0016�E1���qA{��\b�&��", 55 | "b3": { 56 | "op": 136 57 | }, 58 | "b4": { 59 | "op": 172 60 | }, 61 | "str": "OP_DUP OP_HASH160 7e4616b7453185a5f071417bb4ac08e226dbef98 OP_EQUALVERIFY OP_CHECKSIG", 62 | "e": { 63 | "v": 4129604, 64 | "i": 1, 65 | "a": "1CWg72ETzxXwwZaQUdKzC9jrDjTjFxu2K8" 66 | } 67 | } 68 | ] 69 | } 70 | } 71 | ] 72 | -------------------------------------------------------------------------------- /packages/transaction/lib/input.js: -------------------------------------------------------------------------------- 1 | const _ = require('@keyring/util'); 2 | 3 | const Script = require('./script'); 4 | 5 | class Input { 6 | get chain() { return this.constructor.chain; } 7 | static get chain() { return { Script }; } 8 | 9 | constructor(raw={}, subscript, amount) { 10 | if (_.r.is(Input, raw)) { raw = raw.buf; } 11 | if (_.r.is(Buffer, raw) || typeof raw === 'string') { 12 | return new _.Parser(Input).parse(raw); 13 | } 14 | 15 | this.raw = raw; 16 | this.raw.amount = amount; 17 | this.raw.subscript = subscript; 18 | 19 | if (!_.r.isNil(subscript)) { this.subscript = new this.chain.Script(subscript); } 20 | if (!_.r.isNil(amount)) { this.amount = new _.bn(amount); } 21 | 22 | this.txid = this.raw.txid; 23 | this.index = this.raw.index; 24 | this.script = new this.chain.Script(this.raw.script); 25 | 26 | return this; 27 | } 28 | 29 | get sequence() { return _.r.isNil(this.raw.sequence) ? 0xffffffff : this.raw.sequence; } 30 | get complete() { return !_.r.isNil(this.subscript) && !_.r.isNil(this.amount); } 31 | 32 | get buf() { 33 | return new _.Writer() 34 | .reverse(this.txid) 35 | .uint32le(this.index) 36 | .vardata(this.script.buf) 37 | .uint32le(this.sequence) 38 | .buf; 39 | } 40 | 41 | get hex() { return this.buf.toString('hex'); } 42 | 43 | get source() { 44 | if (_.r.isNil(this.subscript)) { 45 | return this.script.source; 46 | } else { 47 | return this.subscript.destination; 48 | } 49 | } 50 | 51 | blank() { this.script = new this.chain.Script(); } 52 | 53 | signableBy(key) { 54 | let complete = this.complete; 55 | let source =this.source[0].toString('hex'); 56 | 57 | let compressedHash = _.ecc.sha256ripemd160(_.ecc.publicKey(key, true)).toString('hex'); 58 | let uncompressedHash = _.ecc.sha256ripemd160(_.ecc.publicKey(key, false)).toString('hex'); 59 | 60 | let signable = false; 61 | let compressed = null; 62 | 63 | if (complete && source === compressedHash) { 64 | signable = true; 65 | compressed = true; 66 | } else if (complete && source === uncompressedHash) { 67 | signable = true; 68 | compressed = false; 69 | } 70 | 71 | return { 72 | source, 73 | signable, 74 | complete, 75 | compressed 76 | }; 77 | 78 | } 79 | 80 | static template() { 81 | return [ 82 | ['txid', 'reverse:32'], 83 | ['index', 'uint32le'], 84 | ['script', 'vardata'], 85 | ['sequence', 'uint32le'] 86 | ]; 87 | } 88 | 89 | static for(chain) { 90 | chain.Script = chain.Script || Script.for(chain); 91 | 92 | class InputClass extends Input { 93 | static get chain() { return chain; } 94 | } 95 | 96 | return InputClass; 97 | } 98 | } 99 | 100 | module.exports = Input; 101 | -------------------------------------------------------------------------------- /packages/bsv/README.md: -------------------------------------------------------------------------------- 1 | # Keyring BSV javascript library 2 | 3 | KeyRing is a javascript library for creating and signing bitcoin transactions, allowing you to easily build wallets for the Bitcoin SV blockchain. The library includes support for the larger OP_RETURN size. With KeyRing it is very easy to add new op codes and script templates because of the projects modular nature. 4 | 5 | ### To add Keyring BSV to your javascript project: 6 | npm 7 | ``` 8 | npm install @keyring/bsv --save 9 | ``` 10 | 11 | yarn 12 | ``` 13 | yarn add @keyring/bsv 14 | ``` 15 | 16 | ### Reference the Transaction package 17 | Add a require reference at the top of your code. 18 | ``` 19 | const BSV = require('@keyring/bsv'); 20 | const Transaction = BSV.Transaction; 21 | ``` 22 | 23 | 24 | ### Instantiate a new Transaction object 25 | You can create a new transaction object by passing in a buffer or a hex string representation of an existing blockchain transaction. 26 | ``` 27 | let txin = new Transaction(hexData); 28 | ``` 29 | 30 | Another option is to pass in an Output object into the Transaction.from() method. You can also pass an array of outputs into the Transaction.from method. The amount is specified in satoshi. 31 | ``` 32 | let tx = new Transaction().from( 33 | { 34 | txid: '729b4706357b70c6aae58cd556e895d9441a7741aeb9436419ecaf18e764ea41', 35 | index: 2, 36 | asm: 'OP_DUP OP_HASH160 108748bafaa372bcaa21b1858eccc78b54fcd371 OP_EQUALVERIFY OP_CHECKSIG', 37 | amount: 1638569 38 | } 39 | ); 40 | ``` 41 | 42 | ### Set the “to” address 43 | The address value should be in the standard address format, passed in as a string. Also include the amount of crypto being sent to that address. 44 | ``` 45 | tx.to(address, satoshis); 46 | ``` 47 | 48 | 49 | ### Set the fee 50 | Use 0 if you want the library to auto calculate the proper fee. 51 | ``` 52 | tx.fee(0); 53 | ``` 54 | 55 | ### Specify the change address 56 | The address value should be in the standard address format, passed in as a string. 57 | ``` 58 | tx.change(address); 59 | ``` 60 | 61 | ### Set OP_RETURN data 62 | Set data into the OP_RETURN as a node.js Buffer value. 63 | ``` 64 | tx.data(Buffer.from(myDataAsString)); 65 | ``` 66 | 67 | Set B:// protocol formatted file data into the OP_RETURN. 68 | ``` 69 | tx.files(rawData, 'image/jpg', 'rockies.jpg', 'binary'); 70 | ``` 71 | The arguments for the files method are: 72 | * file data as a Buffer 73 | * file type 74 | * file name 75 | * encoding 76 | 77 | Example file type values: image/jpg, text/plain, application/octet-stream, application/msgpack, application/cbor 78 | Example encoding values: binary, hex 79 | 80 | Both the MsgPack and CBOR plugins will recognize the B:// protocol format when reading in a raw transaction and will parse the file data if the file type is set to application/msgpack or application/cbor respectively. 81 | 82 | 83 | ### Sign and Serialize the Transaction 84 | Sign with the private key as a node.js Buffer value, and then serialize the transaction. You can then broadcast it using a SPV server’s API. 85 | ``` 86 | tx.sign(privKey); 87 | const serializedTx = tx.hex; 88 | // send serializedTx... 89 | ``` 90 | 91 | ### Chaining together method calls 92 | Note that you can also chain together Transaction method calls, for example: 93 | ``` 94 | tx.to(address, satoshis).change(address).data(Buffer.from(myDataAsString)); 95 | ``` 96 | 97 | -------------------------------------------------------------------------------- /packages/transaction/test/script.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const expect = chai.expect; 3 | 4 | const Script = require('../lib/script'); 5 | const Chain = require('@keyring/chain'); 6 | const chain = new Chain(); 7 | 8 | const p2pkh = '76a914c86a5e5deaeefc79ef444d40bb896f7c6253e8ab88ac'; 9 | const p2pkh_asm = 'OP_DUP OP_HASH160 c86a5e5deaeefc79ef444d40bb896f7c6253e8ab OP_EQUALVERIFY OP_CHECKSIG'; 10 | const p2pkh_codes = Buffer.from('76a91488ac', 'hex'); 11 | 12 | const p2pkhm = '76a91459288e0ec97813bab904867cdcae0d681f6cce5188ac1c73706b71ca325ab67a8f1decb61546a8950da859a08601000000000075'; 13 | const p2pkhm_meta = '73706b71ca325ab67a8f1decb61546a8950da859a086010000000000'; 14 | 15 | describe('Script', () => { 16 | describe('#instance', () => { 17 | it('should return a Script instance', () => { 18 | let script = new Script(); 19 | expect(script).to.be.an.instanceof(Script); 20 | }); 21 | 22 | it('should parse a script', () => { 23 | let script = new Script(p2pkh); 24 | expect(script.hex).to.equal(p2pkh); 25 | }); 26 | 27 | it('should build a script by type', () => { 28 | let script = new Script('p2pkh', 'c86a5e5deaeefc79ef444d40bb896f7c6253e8ab'); 29 | expect(script.hex).to.equal(p2pkh); 30 | }); 31 | 32 | it('should build a script from asm', () => { 33 | let script = new Script('asm', 'OP_DUP OP_HASH160 0c398db55f3edd131431d175e665f252d05b6c3d OP_EQUALVERIFY OP_CHECKSIG'); 34 | expect(script.hex).to.equal('76a9140c398db55f3edd131431d175e665f252d05b6c3d88ac'); 35 | }); 36 | }); 37 | 38 | describe('#for', () => { 39 | it('should create a class with chain set', () => { 40 | let script = new (Script.for(chain))(''); 41 | expect(script.chain).to.eql(chain); 42 | }); 43 | }); 44 | 45 | describe('opcodes', () => { 46 | it('should break a raw script into opscodes', () => { 47 | let script = new Script(p2pkh); 48 | expect(script.opcodes.length).to.equal(5); 49 | }); 50 | }); 51 | 52 | describe('buf', () => { 53 | it('should return the script buffer', () => { 54 | let script = new Script(p2pkh); 55 | expect(script.buf).to.eql(Buffer.from(p2pkh, 'hex')); 56 | }); 57 | }); 58 | 59 | describe('hex', () => { 60 | it('should return the script as hex', () => { 61 | let script = new Script(p2pkh); 62 | expect(script.hex).to.equal(p2pkh); 63 | }); 64 | }); 65 | 66 | describe('asm', () => { 67 | it('should return a human readable version of the script', () => { 68 | let script = new Script(p2pkh); 69 | expect(script.asm).to.equal(p2pkh_asm); 70 | }); 71 | }); 72 | 73 | describe('fingerprint', () => { 74 | it('should return the fingerprint', () => { 75 | let script = new Script(p2pkh); 76 | expect(script.fingerprint).to.equal('OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG'); 77 | }); 78 | }); 79 | 80 | describe('template', () => { 81 | it('should detect p2pkh scripts', () => { 82 | let script = new Script(p2pkh); 83 | expect(script.template.id).to.equal('p2pkh'); 84 | }); 85 | 86 | it('should detect p2pkhm scripts', () => { 87 | let script = new Script(p2pkhm); 88 | expect(script.template.id).to.equal('p2pkhm'); 89 | }); 90 | }); 91 | 92 | describe('meta', () => { 93 | it('should return an object of metadata for p2pkhm', () => { 94 | let script = new Script(p2pkhm); 95 | expect(script.meta.id).to.eql('spkq'); 96 | }); 97 | }); 98 | 99 | describe('destination', () => { 100 | it('should return an array of destinations', () => { 101 | let script = new Script(p2pkhm); 102 | expect(script.destination[0].toString('hex')).to.eql('59288e0ec97813bab904867cdcae0d681f6cce51'); 103 | }); 104 | }); 105 | 106 | }); 107 | -------------------------------------------------------------------------------- /packages/chain/lib/standard-templates.js: -------------------------------------------------------------------------------- 1 | const _ = require('@keyring/util'); 2 | _.ecc = require('ecc-tools'); 3 | 4 | const StandardTemplates = [ 5 | { 6 | id: 'p2pkh', 7 | fingerprint: 'OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG', 8 | patterns: ['OP_DUP OP_HASH160 DATA OP_EQUALVERIFY OP_CHECKSIG'], 9 | destination(script) { return [script.opcodes[2].data]; }, 10 | init(hash) { 11 | hash = _.r.is(Buffer, hash) ? hash.toString('hex') : hash; 12 | return new _.Writer('76a914' + hash + '88ac').buf; 13 | } 14 | }, 15 | { 16 | id: 'p2pkhm', 17 | fingerprint: 'OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG OP_DROP', 18 | patterns: ['OP_DUP OP_HASH160 DATA OP_EQUALVERIFY OP_CHECKSIG DATA OP_DROP'], 19 | destination: (script) => { return [script.opcodes[2].data]; }, 20 | meta: (script) => { 21 | let data = new _.Reader(script.opcodes[5].data); 22 | let identifier = data.read(4).toString(); 23 | if (identifier === 'spkq') { 24 | let assets = {}; 25 | while (!data.eof) { 26 | assets[data.reverse(16).toString('hex')] = data.uint64le().toNumber(); 27 | } 28 | return {type: 'mc-asset', id: identifier, assets: assets, data: data.buf}; 29 | } else if (identifier === 'spkg') { 30 | return { type: 'mc-issuance-quantity', id: identifier, quantity: data.uint64le() }; 31 | } else { return {type: 'raw', data: data.buf}; } 32 | } 33 | }, 34 | { 35 | id: 'data', 36 | fingerprint: 'OP_RETURN ', 37 | patterns: [ 38 | 'OP_RETURN DATA', 39 | 'OP_RETURN DATA DATA', 40 | 'OP_RETURN DATA DATA DATA', 41 | 'OP_RETURN DATA DATA DATA DATA', 42 | 'OP_RETURN DATA DATA DATA DATA DATA', 43 | 'OP_RETURN DATA DATA DATA DATA DATA DATA', 44 | 'OP_RETURN DATA DATA DATA DATA DATA DATA DATA', 45 | 'OP_RETURN DATA DATA DATA DATA DATA DATA DATA DATA' 46 | ], 47 | data(script) { 48 | let data = _.r.pluck('data', script.opcodes); 49 | data.shift(); 50 | return data; 51 | }, 52 | init(...data) { 53 | data = this.chain.opcodes.fromData(...data); 54 | data.unshift(this.chain.opcodes.get('OP_RETURN')[0]); 55 | return Buffer.concat(_.r.pluck('buf', data)); 56 | } 57 | }, 58 | { 59 | id: 'false-data', 60 | fingerprint: 'OP_FALSE OP_RETURN ', 61 | patterns: [ 62 | 'OP_FALSE OP_RETURN DATA', 63 | 'OP_FALSE OP_RETURN DATA DATA', 64 | 'OP_FALSE OP_RETURN DATA DATA DATA', 65 | 'OP_FALSE OP_RETURN DATA DATA DATA DATA', 66 | 'OP_FALSE OP_RETURN DATA DATA DATA DATA DATA', 67 | 'OP_FALSE OP_RETURN DATA DATA DATA DATA DATA DATA', 68 | 'OP_FALSE OP_RETURN DATA DATA DATA DATA DATA DATA DATA', 69 | 'OP_FALSE OP_RETURN DATA DATA DATA DATA DATA DATA DATA DATA' 70 | ], 71 | data(script) { 72 | let data = _.r.pluck('data', script.opcodes); 73 | data.shift(); 74 | data.shift(); 75 | return data; 76 | }, 77 | init(...data) { 78 | data = this.chain.opcodes.fromData(...data); 79 | data.unshift(this.chain.opcodes.get('OP_RETURN')[0]); 80 | data.unshift(this.chain.opcodes.get('OP_FALSE')[0]); 81 | return Buffer.concat(_.r.pluck('buf', data)); 82 | } 83 | }, 84 | { 85 | id: 'blank', 86 | fingerprint: '', 87 | patterns: [''], 88 | init() { return Buffer.alloc(0); } 89 | }, 90 | { 91 | id: 'signature', 92 | fingerprint: ' ', 93 | patterns: ['SIGNATURE PUBKEY'], 94 | source(script) { 95 | return [_.ecc.sha256ripemd160(script.opcodes[1].data)]; 96 | }, 97 | init(key, sighash, type, compressed=true) { 98 | key = _.r.is(String, key) ? Buffer.from(key, 'hex') : key; 99 | 100 | let _type = Buffer.alloc(1); 101 | _type.writeUInt8(type, 0); 102 | 103 | let pub = _.ecc.publicKey(key, compressed); 104 | let signature = Buffer.concat([_.ecc.sign(sighash, key), _type]); 105 | 106 | return ( 107 | signature.length.toString(16) + 108 | signature.toString('hex') + 109 | pub.length.toString(16) + 110 | pub.toString('hex') 111 | ); 112 | } 113 | } 114 | ]; 115 | 116 | module.exports = StandardTemplates; 117 | -------------------------------------------------------------------------------- /packages/transaction/lib/sighash.js: -------------------------------------------------------------------------------- 1 | const _ = require('@keyring/util'); 2 | _.ecc = require('ecc-tools'); 3 | _.hash = _.ecc; 4 | 5 | class Sighash { 6 | constructor(tx='') { this.tx = tx; } 7 | 8 | get _prevouts() { 9 | return _.r.reduce((memo, input) => { 10 | memo.reverse(input.txid).uint32le(input.index); 11 | return memo; 12 | }, new _.Writer(), this.tx.inputs).buf; 13 | } 14 | 15 | get prevouts() { return _.hash.sha256sha256(this._prevouts); } 16 | 17 | get _sequence() { 18 | return _.r.reduce((memo, input) => { 19 | memo.uint32le(input.sequence); 20 | return memo; 21 | }, new _.Writer(), this.tx.inputs).buf; 22 | } 23 | 24 | get sequence() { return _.hash.sha256sha256(this._sequence); } 25 | 26 | get _outputs() { 27 | return _.r.reduce((memo, output) => { 28 | memo.write(output.buf); 29 | return memo; 30 | }, new _.Writer(), this.tx.outputs).buf; 31 | } 32 | 33 | get outputs() { return _.hash.sha256sha256(this._outputs); } 34 | 35 | _bip143(index, subscript, amount, type) { 36 | let tx = this.tx; 37 | let input = tx.inputs[index]; 38 | 39 | let prevouts = Buffer.alloc(32); 40 | let sequence = Buffer.alloc(32); 41 | let outputs = Buffer.alloc(32); 42 | 43 | if (!(type & Sighash.ANYONECANPAY)) { prevouts = this.prevouts; } 44 | 45 | if ( 46 | !(type & Sighash.ANYONECANPAY) && 47 | (type & 0x1f) !== Sighash.SINGLE && 48 | (type & 0x1f) !== Sighash.NONE 49 | ) { sequence = this.sequence; } 50 | 51 | if ((type & 0x1f) !== Sighash.SINGLE && (type & 0x1f) !== Sighash.NONE) { 52 | outputs = this.outputs; 53 | } else if ((type & 0x1f) == Sighash.SINGLE && index < tx.outputs.length) { 54 | outputs = _.hash.sha256sha256(tx.outputs[index].buf); 55 | } 56 | 57 | subscript = _.buf.from(subscript); 58 | 59 | return new _.Writer() 60 | .uint32le(tx.version) 61 | .write(prevouts) 62 | .write(sequence) 63 | .reverse(input.txid) 64 | .uint32le(input.index) 65 | .varint(subscript.length) 66 | .write(subscript) 67 | .uint64le(amount) 68 | .uint32le(input.sequence) 69 | .write(outputs) 70 | .uint32le(tx.locktime) 71 | .uint32le(type >>> 0) 72 | .buf 73 | ; 74 | } 75 | 76 | bip143(index, subscript, amount, type) { 77 | return _.hash.sha256sha256(this._bip143(index, subscript, amount, type)); 78 | } 79 | 80 | _original(index, subscript, amount, type) { 81 | let txcopy = this.tx.clone; 82 | let input = txcopy.inputs[index]; 83 | 84 | _.r.forEach((input) => { input.blank(); }, txcopy.inputs); 85 | 86 | txcopy.inputs[index].script.set(subscript); 87 | 88 | if ((type & 0x1f) === Sighash.NONE || (type & 0x1f) === Sighash.SINGLE) { 89 | _.r.addIndex(_.r.forEach)((input, i) => { 90 | if (i !== index) { input.raw.sequence = 0; } 91 | }, txcopy.inputs); 92 | } 93 | 94 | if ((type & 0x1f) === Sighash.NONE) { txcopy.outputs = []; } 95 | else if ((type & 0x1f) === Sighash.SINGLE) { 96 | if (index >= txcopy.outputs) { 97 | return Sighash.SINGLEBUG; 98 | } 99 | 100 | txcopy.outputs.length = index + 1; 101 | for (let i=0; i < index; i++) { txcopy.outputs[i].blank(); } 102 | } 103 | 104 | if (type & Sighash.ANYONECANPAY) { txcopy.inputs = [txcopy.inputs[index]]; } 105 | return new _.Writer() 106 | .write(txcopy.buf) 107 | .uint32le(type) 108 | .buf; 109 | } 110 | 111 | original(index, subscript, amount, type) { 112 | return _.hash.sha256sha256(this._original(index, subscript, amount, type)); 113 | } 114 | 115 | hash(index, subscript, amount, type) { 116 | if (type & Sighash.FORKID) { return this.bip143(index, subscript, amount, type); } 117 | else { return this.original(index, subscript, amount, type); } 118 | } 119 | }; 120 | 121 | Sighash.ALL = 0x01; 122 | Sighash.NONE = 0x02; 123 | Sighash.SINGLE = 0x03; 124 | Sighash.FORKID = 0x40; 125 | Sighash.ANYONECANPAY = 0x80; 126 | 127 | Sighash.ALLFORKID = Sighash.All | Sighash.FORKID; 128 | Sighash.NONEFORKID = Sighash.NONE | Sighash.FORKID; 129 | Sighash.SINGLEFORKID = Sighash.SINGLE | Sighash.FORKID; 130 | Sighash.ANYONECANPAYFORKID = Sighash.ANYONECANPAY | Sighash.FORKID; 131 | 132 | Sighash.DEFAULT = Sighash.ALLFORKID; 133 | 134 | Sighash.SINGLEBUG = Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex'); 135 | 136 | module.exports = Sighash; 137 | -------------------------------------------------------------------------------- /packages/util/test/writer.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const expect = chai.expect; 3 | 4 | const BN = require('bn.js'); 5 | const Writer = require('../lib/writer'); 6 | 7 | describe('Writer', () => { 8 | describe('#instance', () => { 9 | it('should return a Writer instance', () => { 10 | let writer = new Writer('deadbeef'); 11 | expect(writer).to.be.instanceof(Writer); 12 | }); 13 | 14 | it('should take a buffer as the first argument', () => { 15 | let buf = Buffer.from('deadbeef', 'hex'); 16 | let writer = new Writer(buf); 17 | expect(writer._buf).to.be.instanceof(Buffer); 18 | }); 19 | 20 | it('should take a hex encoded string as the first argument', () => { 21 | let writer = new Writer('deadbeef'); 22 | expect(writer._buf).to.be.instanceof(Buffer); 23 | expect(writer._buf.toString('hex')).to.equal('deadbeef'); 24 | }); 25 | 26 | it('should take a writer as the first argument', () => { 27 | let writer1 = new Writer('deadbeef'); 28 | let writer2 = new Writer(writer1); 29 | expect(writer1).to.equal(writer2); 30 | }); 31 | 32 | it('should error if passed anything other than a hex string or buffer', () => { 33 | expect(() => { new Writer(1); }).to.throw(TypeError); 34 | }); 35 | }); 36 | 37 | 38 | describe('write', () => { 39 | it('should write the bytes', () => { 40 | let writer = new Writer('deadbeef'); 41 | let result = writer.write(Buffer.from('cafe', 'hex')).hex; 42 | expect(result).to.equal('deadbeefcafe'); 43 | }); 44 | 45 | it('should write an array of buffers prepended with the length', () => { 46 | let writer = new Writer('deadbeef'); 47 | let result = writer.write(['ca', 'fe']).hex; 48 | expect(result).to.equal('deadbeef02cafe'); 49 | }); 50 | }); 51 | 52 | describe('reverse', () => { 53 | it('should write the bytes in reverse', () => { 54 | let writer = new Writer('deadbeef'); 55 | let result = writer.reverse('feca').hex; 56 | expect(result).to.equal('deadbeefcafe'); 57 | }); 58 | }); 59 | 60 | describe('vardata', () => { 61 | it('should write the length then the data', () => { 62 | let writer = new Writer('02'); 63 | let result = writer.vardata('deadbeef').hex; 64 | expect(result).to.equal('0204deadbeef'); 65 | }); 66 | }); 67 | 68 | describe('varint', () => { 69 | it('should handle uint8', () => { 70 | let writer = new Writer('01'); 71 | let result = writer.varint(0).varint(252).hex; 72 | expect(result).to.equal('0100fc'); 73 | }); 74 | 75 | it('should handle uint16', () => { 76 | let writer = new Writer('01'); 77 | let result = writer.varint(253).varint(0xffff).hex; 78 | expect(result).to.equal('01fdfd00fdffff'); 79 | }); 80 | 81 | it('should handle uint32', () => { 82 | let writer = new Writer('01'); 83 | let result = writer.varint(0x10000).varint(0xffffffff).hex; 84 | expect(result).to.equal('01fe00000100feffffffff'); 85 | }); 86 | 87 | it('should handle uint64', () => { 88 | let writer = new Writer('01'); 89 | let result = writer.varint(0x100000000).varint(new BN('ffffffffffffffff', 16)).hex; 90 | expect(result).to.equal('01ff0000000001000000ffffffffffffffffff'); 91 | }); 92 | }); 93 | 94 | describe('uint8', () => { 95 | it('should write the uint8 encoded buffer to the end', () => { 96 | let writer = new Writer('ff'); 97 | let result = writer.uint8(0).uint8(100).uint8(255).hex; 98 | expect(result).to.equal('ff0064ff'); 99 | }); 100 | }); 101 | 102 | describe('uint16le', () => { 103 | it('should write the uint8 encoded buffer to the end', () => { 104 | let writer = new Writer('ff'); 105 | let result = writer.uint16le(0).uint16le(100).uint16le(255).hex; 106 | expect(result).to.equal('ff00006400ff00'); 107 | }); 108 | }); 109 | 110 | describe('uint16be', () => { 111 | it('should write the uint8 encoded buffer to the end', () => { 112 | let writer = new Writer('ff'); 113 | let result = writer.uint16be(0).uint16be(100).uint16be(255).hex; 114 | expect(result).to.equal('ff0000006400ff'); 115 | }); 116 | }); 117 | 118 | describe('uint32le', () => { 119 | it('should write the uint8 encoded buffer to the end', () => { 120 | let writer = new Writer('ff'); 121 | let result = writer.uint32le(0).uint32le(100).uint32le(255).hex; 122 | expect(result).to.equal('ff0000000064000000ff000000'); 123 | }); 124 | }); 125 | 126 | describe('uint32be', () => { 127 | it('should write the uint8 encoded buffer to the end', () => { 128 | let writer = new Writer('ff'); 129 | let result = writer.uint32be(0).uint32be(100).uint32be(255).hex; 130 | expect(result).to.equal('ff0000000000000064000000ff'); 131 | }); 132 | }); 133 | }); 134 | -------------------------------------------------------------------------------- /packages/util/test/reader.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const expect = chai.expect; 3 | 4 | const BN = require('bn.js'); 5 | const Reader = require('../lib/reader'); 6 | 7 | describe('Reader', () => { 8 | describe('#instance', () => { 9 | it('should return a Reader instance', () => { 10 | let reader = new Reader('deadbeef'); 11 | expect(reader).to.be.instanceof(Reader); 12 | }); 13 | 14 | it('should take a buffer as the first argument', () => { 15 | let reader = new Reader(Buffer.from('deadbeef', 'hex')); 16 | expect(reader.hex).to.equal('deadbeef'); 17 | }); 18 | 19 | it('should take a hex string as the first argument', () => { 20 | let reader = new Reader('deadbeef'); 21 | expect(reader.hex).to.equal('deadbeef'); 22 | }); 23 | 24 | it('should take a Reader as the first argument and return the same reader', () => { 25 | let reader1 = new Reader('deadbeef'); 26 | let reader2 = new Reader(reader1); 27 | expect(reader1).to.equal(reader2); 28 | }); 29 | }); 30 | 31 | describe('read', () => { 32 | it('should read the bytes', () => { 33 | let reader = new Reader('deadbeef'); 34 | let result = reader.read(2); 35 | expect(result.toString('hex')).to.equal('dead'); 36 | }); 37 | }); 38 | 39 | describe('reverse', () => { 40 | it('should reverse the bytes', () => { 41 | let reader = new Reader('deadbeef'); 42 | let result = reader.reverse(4); 43 | expect(result.toString('hex')).to.equal('efbeadde'); 44 | }); 45 | }); 46 | 47 | describe('compact', () => { 48 | it('should return the first byte if <= 252', () => { 49 | let reader = new Reader('deadbeef'); 50 | let result = reader.compact(); 51 | expect(result.toString('hex')).to.equal('de'); 52 | }); 53 | 54 | it('should return bytes 1-2 if first byte is 253', () => { 55 | let reader = new Reader('fddeadbeefbeefcafe'); 56 | let result = reader.compact(); 57 | expect(result.toString('hex')).to.equal('dead'); 58 | }); 59 | 60 | it('should return bytes 1-4 if first byte is 254', () => { 61 | let reader = new Reader('fedeadbeefbeefcafe'); 62 | let result = reader.compact(); 63 | expect(result.toString('hex')).to.equal('deadbeef'); 64 | }); 65 | 66 | it('should return bytes 1-8 if first byte is 255', () => { 67 | let reader = new Reader('ffdeadbeefbeefcafe'); 68 | let result = reader.compact(); 69 | expect(result.toString('hex')).to.equal('deadbeefbeefcafe'); 70 | }); 71 | }); 72 | 73 | describe('varint', () => { 74 | it('should return a BN', () => { 75 | let reader = new Reader('01'); 76 | let result = reader.varint(); 77 | expect(result).to.be.an.instanceof(BN); 78 | }); 79 | 80 | it('should handle uint8', () => { 81 | let reader = new Reader('01'); 82 | let result = reader.varint(); 83 | expect(result.toNumber()).to.equal(1); 84 | expect(reader._pos).to.equal(1); 85 | }); 86 | 87 | it('should handle uint16', () => { 88 | let reader = new Reader('fd0100'); 89 | let result = reader.varint(); 90 | expect(result.toNumber()).to.equal(1); 91 | expect(reader._pos).to.equal(3); 92 | }); 93 | 94 | it('should handle uint32', () => { 95 | let reader = new Reader('fe01000000'); 96 | let result = reader.varint(); 97 | expect(result.toNumber()).to.equal(1); 98 | expect(reader._pos).to.equal(5); 99 | }); 100 | 101 | it('should handle uint64', () => { 102 | let reader = new Reader('ff0100000000000000'); 103 | let result = reader.varint(); 104 | expect(result.toNumber()).to.equal(1); 105 | expect(reader._pos).to.equal(9); 106 | }); 107 | }); 108 | 109 | describe('vardata', () => { 110 | it('should return the number of bytes recorded in the first byte', () => { 111 | let reader = new Reader('02deadbeef'); 112 | let result = reader.vardata(); 113 | expect(result.toString('hex')).to.equal('dead'); 114 | expect(reader._pos).to.equal(3); 115 | }); 116 | }); 117 | 118 | describe('uint8', () => { 119 | it('should read the current uint8', () => { 120 | let reader = new Reader('ff'); 121 | let result = reader.uint8(); 122 | expect(result).to.equal(255); 123 | expect(reader._pos).to.equal(1); 124 | }); 125 | }); 126 | 127 | describe('uint16le', () => { 128 | it('should read the current uint16le', () => { 129 | let reader = new Reader('01000000'); 130 | let result = reader.uint16le(); 131 | expect(result).to.equal(1); 132 | expect(reader._pos).to.equal(2); 133 | }); 134 | }); 135 | 136 | describe('uint16be', () => { 137 | it('should read the current uint16be', () => { 138 | let reader = new Reader('01000000'); 139 | let result = reader.uint16be(); 140 | expect(result).to.equal(256); 141 | expect(reader._pos).to.equal(2); 142 | }); 143 | }); 144 | 145 | describe('uint32le', () => { 146 | it('should read the current uint32le', () => { 147 | let reader = new Reader('01000000'); 148 | let result = reader.uint32le(); 149 | expect(result).to.equal(1); 150 | expect(reader._pos).to.equal(4); 151 | }); 152 | }); 153 | 154 | describe('uint32be', () => { 155 | it('should read the current uint32be', () => { 156 | let reader = new Reader('00000001'); 157 | let result = reader.uint32be(); 158 | expect(result).to.equal(1); 159 | expect(reader._pos).to.equal(4); 160 | }); 161 | }); 162 | 163 | describe('uint64le', () => { 164 | it('should read the current uint64le', () => { 165 | let reader = new Reader('0100000000000000'); 166 | let result = reader.uint64le(); 167 | expect(result.toNumber()).to.equal(1); 168 | expect(reader._pos).to.equal(8); 169 | }); 170 | }); 171 | 172 | describe('uint64be', () => { 173 | it('should read the current uint64be', () => { 174 | let reader = new Reader('0000000000000001'); 175 | let result = reader.uint64be(); 176 | expect(result.toNumber()).to.equal(1); 177 | expect(reader._pos).to.equal(8); 178 | }); 179 | }); 180 | }); 181 | -------------------------------------------------------------------------------- /packages/transaction/lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const _ = require('@keyring/util'); 4 | _.ecc = require('ecc-tools'); 5 | _.hash = _.ecc; 6 | 7 | const Input = require('./input'); 8 | const Output = require('./output'); 9 | const Script = require('./script'); 10 | const Sighash = require('./sighash'); 11 | 12 | const Plugin = require('@keyring/plugin'); 13 | 14 | class Transaction extends Plugin.Host { 15 | get chain() { return this.constructor.chain; } 16 | set chain(val) { this.constructor.chain = val; } 17 | 18 | get _defaultFeePerKB() { return _.bn.from(1024); } 19 | 20 | static use(provider, refresh) { 21 | this._use(provider, 'transaction', refresh); 22 | } 23 | 24 | constructor(raw={}) { 25 | super('transaction'); 26 | 27 | if (_.r.is(Transaction, raw)) { return raw; } 28 | if (_.r.is(Buffer, raw) || typeof raw === 'string') { 29 | return new _.Parser(this.constructor).parse(raw); 30 | } 31 | 32 | this.raw = Object.assign({ 33 | version: 0x01, 34 | inputs: [], 35 | outputs: [], 36 | locktime: 0 37 | }, raw); 38 | 39 | this.version = this.raw.version; 40 | this.inputs = this.raw.inputs; 41 | this.outputs = this.raw.outputs; 42 | this.locktime = this.raw.locktime; 43 | 44 | this._sighash = new Sighash(this); 45 | 46 | _.r.forEach((output) => { output.tx = this; }, this.outputs); 47 | 48 | return this; 49 | } 50 | 51 | get feePerKB() { return this._feePerKB || this._defaultFeePerKB; } 52 | set feePerKB(fee) { this._feePerKB = _.bn.from(fee); } 53 | 54 | get buf() { 55 | return new _.Writer() 56 | .uint32le(this.version) 57 | .write(this.inputs) 58 | .write(this.outputs) 59 | .uint32le(this.locktime) 60 | .buf; 61 | } 62 | 63 | get hex() { return this.buf.toString('hex'); } 64 | get hash() { return _.hash.sha256sha256(this.buf); } 65 | get id() { return _.buf.reverse(this.hash); } 66 | get txin() { return _.r.pluck('txid', this.inputs); } 67 | get size() { return _.bn.from(this.buf.length); } 68 | 69 | get clone() { return new (this.constructor)(Object.assign({}, this.raw)); } 70 | 71 | get inputAmount() { 72 | return _.r.reduce((total, amount) => { 73 | return total.add(amount); 74 | }, _.bn.Zero, _.r.pluck('amount', this.inputs)); 75 | } 76 | 77 | get outputAmount() { 78 | return _.r.reduce((total, amount) => { 79 | return total.add(amount); 80 | }, _.bn.Zero, _.r.pluck('amount', this.outputs)); 81 | } 82 | 83 | get changeAmount() { 84 | if(_.r.isNil(this._changeIndex)) { 85 | return this.unspent - this.fee; 86 | } else { 87 | return this.outputs[this._changeIndex].amount; 88 | }; 89 | } 90 | 91 | get unspent() { return this.inputAmount.sub(this.outputAmount); } 92 | 93 | get suggestedFee() { 94 | let bytes = this.size.add(_.bn.from(this.inputs.length * 142)); 95 | return bytes.mul(this.feePerKB).div(_.bn.KB).add(_.bn.Byte); 96 | } 97 | 98 | data(...data) { 99 | if(_.r.isEmpty(data)) { 100 | return _.r.pluck('data', this.outputs); 101 | } else { 102 | data = _.r.map((datum) => { 103 | if(_.r.is(Array, datum)) { datum = Buffer.from(datum[0], datum[1]); } 104 | if(_.r.is(String, datum)) { datum = Buffer.from(datum, 'utf8'); } 105 | return datum; 106 | }, data); 107 | let script = new this.chain.Script(this.chain.dataMode, ...data); 108 | this.outputs.push(new Output({ 109 | script, 110 | amount: 0, 111 | tx: this, 112 | index: this.outputs.length 113 | })); 114 | return this; 115 | } 116 | } 117 | 118 | files(data, type, filename, encoding) { 119 | if(_.r.isNil(data)) { 120 | let results = []; 121 | this.data().forEach((datum, index) => { 122 | if( 123 | datum 124 | && datum[0].toString() === '19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut' 125 | ) { 126 | results.push({ 127 | index: index, 128 | data: datum[1], 129 | type: (datum[2] || 'application/octet-stream').toString(), 130 | encoding: (datum[3] || 'binary').toString(), 131 | filename: (datum[4] ? datum[4].toString() : false) 132 | }); 133 | } 134 | }); 135 | return results; 136 | 137 | } else { 138 | if(_.r.is(String, data)) { 139 | if(encoding === 'binary' || encoding === 'hex') { 140 | data = Buffer.from(data, 'hex'); 141 | encoding = 'binary'; 142 | } else { 143 | data = Buffer.from(data, 'UTF-8'); 144 | encoding = encoding || 'UTF-8'; 145 | type = type || 'text/plain'; 146 | } 147 | } 148 | let args = [ 149 | '19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut', 150 | data, 151 | (type || 'application/octet-stream') 152 | ]; 153 | if (filename) { 154 | args.push(encoding || 'binary'); 155 | args.push(filename); 156 | } else if (encoding) { 157 | args.push(encoding); 158 | } 159 | return this.data(...args); 160 | } 161 | } 162 | 163 | fee(amount) { 164 | if (_.r.isNil(amount)) { 165 | return this._fee || this.unspent; 166 | } else { 167 | this._fee = _.bn.from(amount); 168 | return this; 169 | } 170 | } 171 | 172 | to(addr, amount) { 173 | let { hash } = _.addr.from(addr); 174 | let script = new this.chain.Script('p2pkh', hash); 175 | this.outputs.push(new Output({ 176 | script, 177 | amount, 178 | tx: this, 179 | index: this.outputs.length 180 | })); 181 | return this; 182 | } 183 | 184 | from(utxo, sequence) { 185 | if(_.r.is(Array, utxo)) { 186 | _.r.map((output) => { this.from(output); }, utxo); 187 | return this; 188 | } 189 | if(!_.r.is(Output, utxo)) { utxo = new this.chain.Output(utxo); } 190 | let input = new this.chain.Input({ 191 | txid: utxo.txid, 192 | index: utxo.index, 193 | sequence: sequence 194 | }, utxo.script, utxo.amount); 195 | this.inputs.push(input); 196 | return this; 197 | } 198 | 199 | change(addr) { 200 | let { hash } = _.addr.from(addr); 201 | if(_.r.isNil(this._changeIndex)) { 202 | this._changeIndex = this.outputs.length; 203 | this.outputs.push(new this.chain.Output()); 204 | } 205 | 206 | let output = this.outputs[this._changeIndex]; 207 | output.script = new this.chain.Script('p2pkh', hash); 208 | output.amount = this.unspent.sub(this._fee || this.suggestedFee); 209 | 210 | return this; 211 | } 212 | 213 | sign(key, type=Sighash.ALL, useForkid=true) { 214 | if (_.r.is(String, key)) { key = Buffer.from(key, 'hex'); } 215 | if (useForkid) { type = type | Sighash.FORKID; } 216 | 217 | _.r.addIndex(_.r.forEach)((input, index) => { 218 | let {signable, compressed} = input.signableBy(key); 219 | if (signable) { 220 | let sighash = this.sighash(index, type, useForkid); 221 | input.script = new this.chain.Script('signature', key, sighash, type, compressed); 222 | } 223 | return false; 224 | }, this.inputs); 225 | 226 | return this; 227 | } 228 | 229 | sighash(index, type=Sighash.ALL, useForkid=true) { 230 | if (useForkid) { type = type | Sighash.FORKID; } 231 | 232 | let input = this.inputs[index]; 233 | let subscript = input.subscript; 234 | let amount = input.amount; 235 | 236 | return this._sighash.hash(index, subscript, amount, type); 237 | } 238 | 239 | static template() { 240 | return [ 241 | ['version', 'uint32le'], 242 | ['inputs', [Input]], 243 | ['outputs', [Output]], 244 | ['locktime', 'uint32le'] 245 | ]; 246 | } 247 | 248 | static for(chain) { 249 | chain.Output = Output.for(chain); 250 | chain.Input = Input.for(chain); 251 | chain.Script = Script.for(chain); 252 | 253 | class TransactionClass extends Transaction { 254 | static get chain() { return chain; } 255 | 256 | static template() { 257 | return [ 258 | ['version', 'uint32le'], 259 | ['inputs', [chain.Input]], 260 | ['outputs', [chain.Output]], 261 | ['locktime', 'uint32le'] 262 | ]; 263 | } 264 | } 265 | 266 | return TransactionClass; 267 | } 268 | } 269 | 270 | Transaction.chain = { Input, Output, Script, dataMode: 'false-data' }; 271 | Transaction.Sighash = Sighash; 272 | 273 | module.exports = Transaction; 274 | -------------------------------------------------------------------------------- /packages/transaction/test/index.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const expect = chai.expect; 3 | 4 | const Transaction = require('../lib'); 5 | 6 | const Chain = require('@keyring/chain'); 7 | const chain = new Chain(); 8 | 9 | const _ = require('@keyring/util'); 10 | _.ecc = require('ecc-tools'); 11 | 12 | const txhex = '01000000022ac3f773c664720bae094aa7d8556f1e07de84f1ff018d9a5e103aae3d6df81e010000006a473044022056bc0f32af4343d88ea7013576f333e8e39f0dc1aacf97f21cb5c29491d12ef202204146eaf17a154cb6475e2bca66105f75a4839580b0ddde838a7ea694c06698fb0121026e0b474d8bbef2dfe5a83b53cfd8cd0fe1bc17da82e23196ae2f2c49b0fb3f95ffffffff218a162993abf115f7abc612c2413fcb5651db9af10c182fc9b0fefe810a21c6000000006b483045022100d205bc07f5a6bf8f109802bd7483579812390a373bf1096a507c98efde09cdc002201d578583c59a080af9f3db96d8661b3f12f0fbb757d7c3d4e95e34024a67fbdc01210273b8a116a7ec90958cb96047b1232e8b44f69cd9f11c58d27fb8f7fe181352a0ffffffff0200105e5f0000000017a9143ff6616dd58714da04c30447bf04248a2b0e8a9e87555c8e12050000001976a914d02fd16d61fa29d0ff1aef12c980545887ef368a88ac00000000'; 13 | const txhash = 'bd31363bcc28b4d11539f30a2a074bf303d018b5a49e80bc03208fb3b4c7bc82'; 14 | const txid = '82bcc7b4b38f2003bc809ea4b518d003f34b072a0af33915d1b428cc3b3631bd'; 15 | const txin = '1ef86d3dae3a105e9a8d01fff184de071e6f55d8a74a09ae0b7264c673f7c32a'; 16 | const addr = '1KynqMpA5e5h3uy69fayPQkVVm9toePm4y'; 17 | const key = _.ecc.privateKey(); 18 | 19 | const private_key = _.ecc.sha256('hello world'); 20 | const public_key = _.ecc.publicKey(private_key, true); 21 | const sighash = _.ecc.sha256(public_key); 22 | const signature = _.ecc.sign(sighash, private_key); 23 | 24 | const hash = _.ecc.sha256ripemd160(public_key); 25 | 26 | describe('Transaction', () => { 27 | describe('#instance', () => { 28 | it('should return a Transaction instance', () => { 29 | let tx = new Transaction(); 30 | expect(tx).to.be.instanceof(Transaction); 31 | }); 32 | 33 | it('should parse a hex string', () => { 34 | let tx = new Transaction(txhex); 35 | expect(tx.version).to.equal(1); 36 | expect(tx.inputs.length).to.eql(2); 37 | expect(tx.outputs.length).to.eql(2); 38 | }); 39 | }); 40 | 41 | describe('#for', () => { 42 | it('should create a class with chain set', () => { 43 | let tx = new (Transaction.for(chain))(txhex); 44 | expect(tx.inputs[0].chain.Script).to.be.not.null; 45 | }); 46 | }); 47 | 48 | describe('buf', () => { 49 | it('should return the buffer for the transaction', () => { 50 | let tx = new Transaction(txhex); 51 | expect(tx.buf.toString('hex')).to.eql(txhex); 52 | }); 53 | }); 54 | 55 | describe('hash', () => { 56 | it('should return the hash for the transaction', () => { 57 | let tx = new Transaction(txhex); 58 | expect(tx.hash.toString('hex')).to.eql(txhash); 59 | }); 60 | }); 61 | 62 | describe('id', () => { 63 | it('should return the id for the transaction', () => { 64 | let tx = new Transaction(txhex); 65 | expect(tx.id.toString('hex')).to.eql(txid); 66 | }); 67 | }); 68 | 69 | describe('txin', () => { 70 | it('should return the transaction ids for each input', () => { 71 | let tx = new Transaction(txhex); 72 | let result = tx.txin; 73 | expect(result.length).to.eql(2); 74 | expect(result[0].toString('hex')).to.eql(txin); 75 | }); 76 | }); 77 | 78 | describe('to', () => { 79 | it('should add new output', () => { 80 | let tx = new Transaction(); 81 | tx.to(addr, 10); 82 | expect(tx.outputs.length).to.eql(1); 83 | expect(tx.outputs[0].script.hex).to.equal('76a914' + _.addr.from(addr).hash.toString('hex') + '88ac'); 84 | }); 85 | }); 86 | 87 | describe('from', () => { 88 | it('should add an input', () => { 89 | let tx = new Transaction(); 90 | let txin = new Transaction(txhex); 91 | tx.from(txin.outputs[1]); 92 | expect(tx.inputs.length).to.eql(1); 93 | expect(tx.inputs[0].script.hex).to.equal(''); 94 | expect(tx.inputs[0].amount.toNumber()).to.equal(21786156117); 95 | }); 96 | 97 | it('should take an array', () => { 98 | let tx = new Transaction(); 99 | let txin = new Transaction(txhex); 100 | tx.from([txin.outputs[1]]); 101 | expect(tx.inputs.length).to.eql(1); 102 | expect(tx.inputs[0].script.hex).to.equal(''); 103 | expect(tx.inputs[0].amount.toNumber()).to.equal(21786156117); 104 | }); 105 | 106 | it('should take an object', () => { 107 | let tx = new Transaction(); 108 | let txin = new Transaction(txhex); 109 | tx.from({ 110 | txid: txin.id, 111 | index: 0, 112 | asm: 'OP_DUP OP_HASH160 3ff6616dd58714da04c30447bf04248a2b0e8a9e OP_EQUALVERIFY OP_CHECKSIG', 113 | amount: 100 114 | }); 115 | expect(tx.inputs.length).to.eql(1); 116 | expect(tx.inputs[0].script.hex).to.equal(''); 117 | expect(tx.inputs[0].subscript.hex).to.equal('76a9143ff6616dd58714da04c30447bf04248a2b0e8a9e88ac'); 118 | expect(tx.inputs[0].amount.toNumber()).to.equal(100); 119 | }); 120 | }); 121 | 122 | describe('fee', () => { 123 | it('should return the current fee', () => { 124 | let tx = new Transaction(); 125 | let txin = new Transaction(txhex); 126 | tx.from(txin.outputs[1]); 127 | tx.to(addr, 100); 128 | expect(tx.fee().toNumber()).to.equal(21786156017); 129 | }); 130 | }); 131 | 132 | describe('change', () => { 133 | it('should add a change output', () => { 134 | let tx = new Transaction(); 135 | let txin = new Transaction(txhex); 136 | tx.from(txin.outputs[1]); 137 | tx.change(addr); 138 | expect(tx.fee().toNumber()).to.equal(tx.suggestedFee.toNumber()); 139 | }); 140 | }); 141 | 142 | describe('data', () => { 143 | it('should add data output', () => { 144 | let tx = new Transaction(); 145 | let txin = new Transaction(txhex); 146 | tx.from(txin.outputs[1]); 147 | tx.data(Buffer.from('deadbeef', 'hex')); 148 | expect(tx.data()[0][0].toString('hex')).to.equal('deadbeef'); 149 | }); 150 | 151 | it('should add multiple data pushes to a single output', () => { 152 | let tx = new Transaction(); 153 | let txin = new Transaction(txhex); 154 | tx.from(txin.outputs[1]); 155 | tx.data('hello', 'world'); 156 | expect(tx.data()[0][0].toString('utf8')).to.equal('hello'); 157 | expect(tx.data()[0][1].toString('utf8')).to.equal('world'); 158 | }); 159 | }); 160 | 161 | describe('file', () => { 162 | it('should add file output for String', () => { 163 | let tx = new Transaction(); 164 | let txin = new Transaction(txhex); 165 | tx.from(txin.outputs[1]); 166 | tx.files('hello world'); 167 | expect(tx.data()[0][1].toString()).to.equal('hello world'); 168 | }); 169 | 170 | it('should add file output for Buffer', () => { 171 | let tx = new Transaction(); 172 | let txin = new Transaction(txhex); 173 | tx.from(txin.outputs[1]); 174 | tx.files(Buffer.from('deadbeef', 'hex')); 175 | expect(tx.data()[0][1]).to.eql(Buffer.from('deadbeef', 'hex')); 176 | }); 177 | 178 | it('should add file output for larger Buffer', () => { 179 | let tx = new Transaction(); 180 | let txin = new Transaction(txhex); 181 | tx.from(txin.outputs[1]); 182 | tx.files(Buffer.alloc(1024), 'text/plain'); 183 | expect(tx.data()[0][1]).to.eql(Buffer.alloc(1024)); 184 | expect(tx.data()[0][2].toString()).to.eql('text/plain'); 185 | }); 186 | 187 | it('should read files', () => { 188 | let tx = new Transaction(); 189 | let txin = new Transaction(txhex); 190 | tx.from(txin.outputs[1]); 191 | tx.files('{ "hello": "world" }', 'application/json', 'test.json'); 192 | expect(tx.files()[0].data.toString()).to.equal('{ "hello": "world" }'); 193 | expect(tx.files()[0].type).to.equal('application/json'); 194 | expect(tx.files()[0].encoding).to.equal('UTF-8'); 195 | expect(tx.files()[0].filename).to.equal('test.json'); 196 | }); 197 | }); 198 | 199 | describe('sign', () => { 200 | it('should sign all possible inputs', () => { 201 | let inAddr = _.addr.format(hash); 202 | let txin = new Transaction().to(inAddr, 1000).to(inAddr, 100); 203 | let tx = new Transaction().from(txin.outputs[0]); 204 | let sighash = tx.sighash(0, 0x01, false); 205 | let signature = _.ecc.sign((sighash), private_key); 206 | let scriptsig = '47' + signature.toString('hex') + '0121' + public_key.toString('hex'); 207 | let result = tx.sign(private_key, 0x01, false).buf; 208 | 209 | expect(result.toString('hex')).to.eql('0100000001'+txin.hash.toString('hex')+'000000006a'+scriptsig+'ffffffff0000000000'); 210 | }); 211 | }); 212 | }); 213 | -------------------------------------------------------------------------------- /packages/util/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@keyring/util", 3 | "version": "0.0.4", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "assertion-error": { 8 | "version": "1.1.0", 9 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 10 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 11 | "dev": true 12 | }, 13 | "balanced-match": { 14 | "version": "1.0.0", 15 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 16 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 17 | "dev": true 18 | }, 19 | "bn.js": { 20 | "version": "4.11.8", 21 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", 22 | "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" 23 | }, 24 | "brace-expansion": { 25 | "version": "1.1.11", 26 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 27 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 28 | "dev": true, 29 | "requires": { 30 | "balanced-match": "^1.0.0", 31 | "concat-map": "0.0.1" 32 | } 33 | }, 34 | "browser-stdout": { 35 | "version": "1.3.1", 36 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 37 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 38 | "dev": true 39 | }, 40 | "chai": { 41 | "version": "4.2.0", 42 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", 43 | "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", 44 | "dev": true, 45 | "requires": { 46 | "assertion-error": "^1.1.0", 47 | "check-error": "^1.0.2", 48 | "deep-eql": "^3.0.1", 49 | "get-func-name": "^2.0.0", 50 | "pathval": "^1.1.0", 51 | "type-detect": "^4.0.5" 52 | } 53 | }, 54 | "check-error": { 55 | "version": "1.0.2", 56 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", 57 | "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", 58 | "dev": true 59 | }, 60 | "commander": { 61 | "version": "2.15.1", 62 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", 63 | "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", 64 | "dev": true 65 | }, 66 | "concat-map": { 67 | "version": "0.0.1", 68 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 69 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 70 | "dev": true 71 | }, 72 | "debug": { 73 | "version": "3.1.0", 74 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 75 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 76 | "dev": true, 77 | "requires": { 78 | "ms": "2.0.0" 79 | } 80 | }, 81 | "deep-eql": { 82 | "version": "3.0.1", 83 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", 84 | "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", 85 | "dev": true, 86 | "requires": { 87 | "type-detect": "^4.0.0" 88 | } 89 | }, 90 | "diff": { 91 | "version": "3.5.0", 92 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 93 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 94 | "dev": true 95 | }, 96 | "escape-string-regexp": { 97 | "version": "1.0.5", 98 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 99 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 100 | "dev": true 101 | }, 102 | "fs.realpath": { 103 | "version": "1.0.0", 104 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 105 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 106 | "dev": true 107 | }, 108 | "get-func-name": { 109 | "version": "2.0.0", 110 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", 111 | "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", 112 | "dev": true 113 | }, 114 | "glob": { 115 | "version": "7.1.2", 116 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 117 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 118 | "dev": true, 119 | "requires": { 120 | "fs.realpath": "^1.0.0", 121 | "inflight": "^1.0.4", 122 | "inherits": "2", 123 | "minimatch": "^3.0.4", 124 | "once": "^1.3.0", 125 | "path-is-absolute": "^1.0.0" 126 | } 127 | }, 128 | "growl": { 129 | "version": "1.10.5", 130 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", 131 | "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", 132 | "dev": true 133 | }, 134 | "has-flag": { 135 | "version": "3.0.0", 136 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 137 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 138 | "dev": true 139 | }, 140 | "he": { 141 | "version": "1.1.1", 142 | "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", 143 | "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", 144 | "dev": true 145 | }, 146 | "inflight": { 147 | "version": "1.0.6", 148 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 149 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 150 | "dev": true, 151 | "requires": { 152 | "once": "^1.3.0", 153 | "wrappy": "1" 154 | } 155 | }, 156 | "inherits": { 157 | "version": "2.0.3", 158 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 159 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 160 | "dev": true 161 | }, 162 | "minimatch": { 163 | "version": "3.0.4", 164 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 165 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 166 | "dev": true, 167 | "requires": { 168 | "brace-expansion": "^1.1.7" 169 | } 170 | }, 171 | "minimist": { 172 | "version": "0.0.8", 173 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 174 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 175 | "dev": true 176 | }, 177 | "mkdirp": { 178 | "version": "0.5.1", 179 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 180 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 181 | "dev": true, 182 | "requires": { 183 | "minimist": "0.0.8" 184 | } 185 | }, 186 | "mocha": { 187 | "version": "5.2.0", 188 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", 189 | "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", 190 | "dev": true, 191 | "requires": { 192 | "browser-stdout": "1.3.1", 193 | "commander": "2.15.1", 194 | "debug": "3.1.0", 195 | "diff": "3.5.0", 196 | "escape-string-regexp": "1.0.5", 197 | "glob": "7.1.2", 198 | "growl": "1.10.5", 199 | "he": "1.1.1", 200 | "minimatch": "3.0.4", 201 | "mkdirp": "0.5.1", 202 | "supports-color": "5.4.0" 203 | } 204 | }, 205 | "ms": { 206 | "version": "2.0.0", 207 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 208 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 209 | "dev": true 210 | }, 211 | "once": { 212 | "version": "1.4.0", 213 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 214 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 215 | "dev": true, 216 | "requires": { 217 | "wrappy": "1" 218 | } 219 | }, 220 | "path-is-absolute": { 221 | "version": "1.0.1", 222 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 223 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 224 | "dev": true 225 | }, 226 | "pathval": { 227 | "version": "1.1.0", 228 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", 229 | "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", 230 | "dev": true 231 | }, 232 | "ramda": { 233 | "version": "0.26.1", 234 | "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz", 235 | "integrity": "sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==" 236 | }, 237 | "supports-color": { 238 | "version": "5.4.0", 239 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", 240 | "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", 241 | "dev": true, 242 | "requires": { 243 | "has-flag": "^3.0.0" 244 | } 245 | }, 246 | "type-detect": { 247 | "version": "4.0.8", 248 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 249 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 250 | "dev": true 251 | }, 252 | "wrappy": { 253 | "version": "1.0.2", 254 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 255 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 256 | "dev": true 257 | } 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /packages/transaction/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@keyring/transaction", 3 | "version": "0.0.4", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@keyring/util": { 8 | "version": "0.0.4", 9 | "requires": { 10 | "bn.js": "^4.11.8", 11 | "ramda": "^0.26.1" 12 | } 13 | }, 14 | "assertion-error": { 15 | "version": "1.1.0", 16 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 17 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 18 | "dev": true 19 | }, 20 | "balanced-match": { 21 | "version": "1.0.0", 22 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 23 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 24 | "dev": true 25 | }, 26 | "base-x": { 27 | "version": "3.0.5", 28 | "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.5.tgz", 29 | "integrity": "sha512-C3picSgzPSLE+jW3tcBzJoGwitOtazb5B+5YmAxZm2ybmTi9LNgAtDO/jjVEBZwHoXmDBZ9m/IELj3elJVRBcA==", 30 | "requires": { 31 | "safe-buffer": "^5.0.1" 32 | } 33 | }, 34 | "bindings": { 35 | "version": "1.5.0", 36 | "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", 37 | "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", 38 | "requires": { 39 | "file-uri-to-path": "1.0.0" 40 | } 41 | }, 42 | "bip66": { 43 | "version": "1.1.5", 44 | "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz", 45 | "integrity": "sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=", 46 | "requires": { 47 | "safe-buffer": "^5.0.1" 48 | } 49 | }, 50 | "bn.js": { 51 | "version": "4.11.8", 52 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", 53 | "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" 54 | }, 55 | "brace-expansion": { 56 | "version": "1.1.11", 57 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 58 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 59 | "dev": true, 60 | "requires": { 61 | "balanced-match": "^1.0.0", 62 | "concat-map": "0.0.1" 63 | } 64 | }, 65 | "brorand": { 66 | "version": "1.1.0", 67 | "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", 68 | "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" 69 | }, 70 | "browser-stdout": { 71 | "version": "1.3.1", 72 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 73 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 74 | "dev": true 75 | }, 76 | "browserify-aes": { 77 | "version": "1.2.0", 78 | "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", 79 | "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", 80 | "requires": { 81 | "buffer-xor": "^1.0.3", 82 | "cipher-base": "^1.0.0", 83 | "create-hash": "^1.1.0", 84 | "evp_bytestokey": "^1.0.3", 85 | "inherits": "^2.0.1", 86 | "safe-buffer": "^5.0.1" 87 | } 88 | }, 89 | "bs58": { 90 | "version": "4.0.1", 91 | "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", 92 | "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", 93 | "requires": { 94 | "base-x": "^3.0.2" 95 | } 96 | }, 97 | "bs58check": { 98 | "version": "2.1.2", 99 | "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", 100 | "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", 101 | "requires": { 102 | "bs58": "^4.0.0", 103 | "create-hash": "^1.1.0", 104 | "safe-buffer": "^5.1.2" 105 | } 106 | }, 107 | "buffer-xor": { 108 | "version": "1.0.3", 109 | "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", 110 | "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" 111 | }, 112 | "chai": { 113 | "version": "4.2.0", 114 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", 115 | "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", 116 | "dev": true, 117 | "requires": { 118 | "assertion-error": "^1.1.0", 119 | "check-error": "^1.0.2", 120 | "deep-eql": "^3.0.1", 121 | "get-func-name": "^2.0.0", 122 | "pathval": "^1.1.0", 123 | "type-detect": "^4.0.5" 124 | } 125 | }, 126 | "chai-bignumber": { 127 | "version": "3.0.0", 128 | "resolved": "https://registry.npmjs.org/chai-bignumber/-/chai-bignumber-3.0.0.tgz", 129 | "integrity": "sha512-SubOtaSI2AILWTWe2j0c6i2yFT/f9J6UBjeVGDuwDiPLkF/U5+/eTWUE3sbCZ1KgcPF6UJsDVYbIxaYA097MQA==", 130 | "dev": true 131 | }, 132 | "check-error": { 133 | "version": "1.0.2", 134 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", 135 | "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", 136 | "dev": true 137 | }, 138 | "cipher-base": { 139 | "version": "1.0.4", 140 | "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", 141 | "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", 142 | "requires": { 143 | "inherits": "^2.0.1", 144 | "safe-buffer": "^5.0.1" 145 | } 146 | }, 147 | "commander": { 148 | "version": "2.20.0", 149 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", 150 | "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==" 151 | }, 152 | "concat-map": { 153 | "version": "0.0.1", 154 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 155 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 156 | "dev": true 157 | }, 158 | "create-hash": { 159 | "version": "1.2.0", 160 | "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", 161 | "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", 162 | "requires": { 163 | "cipher-base": "^1.0.1", 164 | "inherits": "^2.0.1", 165 | "md5.js": "^1.3.4", 166 | "ripemd160": "^2.0.1", 167 | "sha.js": "^2.4.0" 168 | } 169 | }, 170 | "create-hmac": { 171 | "version": "1.1.7", 172 | "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", 173 | "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", 174 | "requires": { 175 | "cipher-base": "^1.0.3", 176 | "create-hash": "^1.1.0", 177 | "inherits": "^2.0.1", 178 | "ripemd160": "^2.0.0", 179 | "safe-buffer": "^5.0.1", 180 | "sha.js": "^2.4.8" 181 | } 182 | }, 183 | "debug": { 184 | "version": "3.1.0", 185 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 186 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 187 | "dev": true, 188 | "requires": { 189 | "ms": "2.0.0" 190 | } 191 | }, 192 | "deep-eql": { 193 | "version": "3.0.1", 194 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", 195 | "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", 196 | "dev": true, 197 | "requires": { 198 | "type-detect": "^4.0.0" 199 | } 200 | }, 201 | "diff": { 202 | "version": "3.5.0", 203 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 204 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 205 | "dev": true 206 | }, 207 | "drbg.js": { 208 | "version": "1.0.1", 209 | "resolved": "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz", 210 | "integrity": "sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs=", 211 | "requires": { 212 | "browserify-aes": "^1.0.6", 213 | "create-hash": "^1.1.2", 214 | "create-hmac": "^1.1.4" 215 | } 216 | }, 217 | "ecc-tools": { 218 | "version": "1.0.14", 219 | "resolved": "https://registry.npmjs.org/ecc-tools/-/ecc-tools-1.0.14.tgz", 220 | "integrity": "sha512-AooZc42sNbeGc8oPKQHML9cZE55aj85N+qVg+Uv03rKGYE+TcCoTcNB7RcTjzVrfJR4XuoTrOq1HpZ/onqvyAA==", 221 | "requires": { 222 | "bs58": "^4.0.1", 223 | "bs58check": "^2.0.2", 224 | "es6-promise": "^3.2.1", 225 | "json-stable-stringify": "^1.0.1", 226 | "secp256k1": "^3.1.0", 227 | "triplesec": "^3.0.25" 228 | } 229 | }, 230 | "elliptic": { 231 | "version": "6.4.1", 232 | "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", 233 | "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", 234 | "requires": { 235 | "bn.js": "^4.4.0", 236 | "brorand": "^1.0.1", 237 | "hash.js": "^1.0.0", 238 | "hmac-drbg": "^1.0.0", 239 | "inherits": "^2.0.1", 240 | "minimalistic-assert": "^1.0.0", 241 | "minimalistic-crypto-utils": "^1.0.0" 242 | } 243 | }, 244 | "es6-promise": { 245 | "version": "3.3.1", 246 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", 247 | "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=" 248 | }, 249 | "escape-string-regexp": { 250 | "version": "1.0.5", 251 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 252 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 253 | "dev": true 254 | }, 255 | "evp_bytestokey": { 256 | "version": "1.0.3", 257 | "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", 258 | "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", 259 | "requires": { 260 | "md5.js": "^1.3.4", 261 | "safe-buffer": "^5.1.1" 262 | } 263 | }, 264 | "file-uri-to-path": { 265 | "version": "1.0.0", 266 | "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", 267 | "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" 268 | }, 269 | "fs.realpath": { 270 | "version": "1.0.0", 271 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 272 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 273 | "dev": true 274 | }, 275 | "get-func-name": { 276 | "version": "2.0.0", 277 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", 278 | "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", 279 | "dev": true 280 | }, 281 | "glob": { 282 | "version": "7.1.2", 283 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 284 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 285 | "dev": true, 286 | "requires": { 287 | "fs.realpath": "^1.0.0", 288 | "inflight": "^1.0.4", 289 | "inherits": "2", 290 | "minimatch": "^3.0.4", 291 | "once": "^1.3.0", 292 | "path-is-absolute": "^1.0.0" 293 | } 294 | }, 295 | "growl": { 296 | "version": "1.10.5", 297 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", 298 | "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", 299 | "dev": true 300 | }, 301 | "has-flag": { 302 | "version": "3.0.0", 303 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 304 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 305 | "dev": true 306 | }, 307 | "hash-base": { 308 | "version": "3.0.4", 309 | "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", 310 | "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", 311 | "requires": { 312 | "inherits": "^2.0.1", 313 | "safe-buffer": "^5.0.1" 314 | } 315 | }, 316 | "hash.js": { 317 | "version": "1.1.7", 318 | "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", 319 | "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", 320 | "requires": { 321 | "inherits": "^2.0.3", 322 | "minimalistic-assert": "^1.0.1" 323 | } 324 | }, 325 | "he": { 326 | "version": "1.1.1", 327 | "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", 328 | "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", 329 | "dev": true 330 | }, 331 | "hmac-drbg": { 332 | "version": "1.0.1", 333 | "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", 334 | "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", 335 | "requires": { 336 | "hash.js": "^1.0.3", 337 | "minimalistic-assert": "^1.0.0", 338 | "minimalistic-crypto-utils": "^1.0.1" 339 | } 340 | }, 341 | "iced-error": { 342 | "version": "0.0.13", 343 | "resolved": "https://registry.npmjs.org/iced-error/-/iced-error-0.0.13.tgz", 344 | "integrity": "sha512-yEEaG8QfyyRL0SsbNNDw3rVgTyqwHFMCuV6jDvD43f/2shmdaFXkqvFLGhDlsYNSolzYHwVLM/CrXt9GygYopA==" 345 | }, 346 | "iced-lock": { 347 | "version": "1.1.0", 348 | "resolved": "https://registry.npmjs.org/iced-lock/-/iced-lock-1.1.0.tgz", 349 | "integrity": "sha1-YRbvHKs6zW5rEIk7snumIv0/3nI=", 350 | "requires": { 351 | "iced-runtime": "^1.0.0" 352 | } 353 | }, 354 | "iced-runtime": { 355 | "version": "1.0.3", 356 | "resolved": "https://registry.npmjs.org/iced-runtime/-/iced-runtime-1.0.3.tgz", 357 | "integrity": "sha1-LU9PuZmreqVDCxk8d6f85BGDGc4=" 358 | }, 359 | "inflight": { 360 | "version": "1.0.6", 361 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 362 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 363 | "dev": true, 364 | "requires": { 365 | "once": "^1.3.0", 366 | "wrappy": "1" 367 | } 368 | }, 369 | "inherits": { 370 | "version": "2.0.3", 371 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 372 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 373 | }, 374 | "json-stable-stringify": { 375 | "version": "1.0.1", 376 | "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", 377 | "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", 378 | "requires": { 379 | "jsonify": "~0.0.0" 380 | } 381 | }, 382 | "jsonify": { 383 | "version": "0.0.0", 384 | "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", 385 | "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" 386 | }, 387 | "md5.js": { 388 | "version": "1.3.5", 389 | "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", 390 | "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", 391 | "requires": { 392 | "hash-base": "^3.0.0", 393 | "inherits": "^2.0.1", 394 | "safe-buffer": "^5.1.2" 395 | } 396 | }, 397 | "minimalistic-assert": { 398 | "version": "1.0.1", 399 | "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", 400 | "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" 401 | }, 402 | "minimalistic-crypto-utils": { 403 | "version": "1.0.1", 404 | "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", 405 | "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" 406 | }, 407 | "minimatch": { 408 | "version": "3.0.4", 409 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 410 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 411 | "dev": true, 412 | "requires": { 413 | "brace-expansion": "^1.1.7" 414 | } 415 | }, 416 | "minimist": { 417 | "version": "0.0.8", 418 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 419 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 420 | "dev": true 421 | }, 422 | "mkdirp": { 423 | "version": "0.5.1", 424 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 425 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 426 | "dev": true, 427 | "requires": { 428 | "minimist": "0.0.8" 429 | } 430 | }, 431 | "mocha": { 432 | "version": "5.2.0", 433 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", 434 | "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", 435 | "dev": true, 436 | "requires": { 437 | "browser-stdout": "1.3.1", 438 | "commander": "2.15.1", 439 | "debug": "3.1.0", 440 | "diff": "3.5.0", 441 | "escape-string-regexp": "1.0.5", 442 | "glob": "7.1.2", 443 | "growl": "1.10.5", 444 | "he": "1.1.1", 445 | "minimatch": "3.0.4", 446 | "mkdirp": "0.5.1", 447 | "supports-color": "5.4.0" 448 | }, 449 | "dependencies": { 450 | "commander": { 451 | "version": "2.15.1", 452 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", 453 | "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", 454 | "dev": true 455 | } 456 | } 457 | }, 458 | "more-entropy": { 459 | "version": "0.0.7", 460 | "resolved": "https://registry.npmjs.org/more-entropy/-/more-entropy-0.0.7.tgz", 461 | "integrity": "sha1-Z7/G96hvJvvDeqyD/UbYjGHRCbU=", 462 | "requires": { 463 | "iced-runtime": ">=0.0.1" 464 | } 465 | }, 466 | "ms": { 467 | "version": "2.0.0", 468 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 469 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 470 | "dev": true 471 | }, 472 | "nan": { 473 | "version": "2.13.2", 474 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz", 475 | "integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==" 476 | }, 477 | "once": { 478 | "version": "1.4.0", 479 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 480 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 481 | "dev": true, 482 | "requires": { 483 | "wrappy": "1" 484 | } 485 | }, 486 | "path-is-absolute": { 487 | "version": "1.0.1", 488 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 489 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 490 | "dev": true 491 | }, 492 | "pathval": { 493 | "version": "1.1.0", 494 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", 495 | "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", 496 | "dev": true 497 | }, 498 | "progress": { 499 | "version": "1.1.8", 500 | "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", 501 | "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=" 502 | }, 503 | "ripemd160": { 504 | "version": "2.0.2", 505 | "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", 506 | "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", 507 | "requires": { 508 | "hash-base": "^3.0.0", 509 | "inherits": "^2.0.1" 510 | } 511 | }, 512 | "safe-buffer": { 513 | "version": "5.1.2", 514 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 515 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 516 | }, 517 | "secp256k1": { 518 | "version": "3.6.2", 519 | "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.6.2.tgz", 520 | "integrity": "sha512-90nYt7yb0LmI4A2jJs1grglkTAXrBwxYAjP9bpeKjvJKOjG2fOeH/YI/lchDMIvjrOasd5QXwvV2jwN168xNng==", 521 | "requires": { 522 | "bindings": "^1.2.1", 523 | "bip66": "^1.1.3", 524 | "bn.js": "^4.11.3", 525 | "create-hash": "^1.1.2", 526 | "drbg.js": "^1.0.1", 527 | "elliptic": "^6.2.3", 528 | "nan": "^2.2.1", 529 | "safe-buffer": "^5.1.0" 530 | } 531 | }, 532 | "sha.js": { 533 | "version": "2.4.11", 534 | "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", 535 | "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", 536 | "requires": { 537 | "inherits": "^2.0.1", 538 | "safe-buffer": "^5.0.1" 539 | } 540 | }, 541 | "source-map": { 542 | "version": "0.6.1", 543 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 544 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" 545 | }, 546 | "supports-color": { 547 | "version": "5.4.0", 548 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", 549 | "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", 550 | "dev": true, 551 | "requires": { 552 | "has-flag": "^3.0.0" 553 | } 554 | }, 555 | "triplesec": { 556 | "version": "3.0.27", 557 | "resolved": "https://registry.npmjs.org/triplesec/-/triplesec-3.0.27.tgz", 558 | "integrity": "sha512-FDhkxa3JYnPOerOd+8k+SBmm7cb7KkyX+xXwNFV3XV6dsQgHuRvjtbnzWfPJ2kimeR8ErjZfPd/6r7RH6epHDw==", 559 | "requires": { 560 | "iced-error": ">=0.0.9", 561 | "iced-lock": "^1.0.1", 562 | "iced-runtime": "^1.0.2", 563 | "more-entropy": ">=0.0.7", 564 | "progress": "~1.1.2", 565 | "uglify-js": "^3.1.9" 566 | } 567 | }, 568 | "type-detect": { 569 | "version": "4.0.8", 570 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 571 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 572 | "dev": true 573 | }, 574 | "uglify-js": { 575 | "version": "3.5.4", 576 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.4.tgz", 577 | "integrity": "sha512-GpKo28q/7Bm5BcX9vOu4S46FwisbPbAmkkqPnGIpKvKTM96I85N6XHQV+k4I6FA2wxgLhcsSyHoNhzucwCflvA==", 578 | "requires": { 579 | "commander": "~2.20.0", 580 | "source-map": "~0.6.1" 581 | } 582 | }, 583 | "wrappy": { 584 | "version": "1.0.2", 585 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 586 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 587 | "dev": true 588 | } 589 | } 590 | } 591 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@keyring/bsv@file:/Users/alex/dev/keyring/packages/bsv": 6 | version "0.2.1" 7 | resolved "file:packages/bsv" 8 | dependencies: 9 | "@keyring/chain" "^0.2.0" 10 | "@keyring/transaction" "^0.2.2" 11 | 12 | "@keyring/chain@^0.2.0", "@keyring/chain@file:/Users/alex/dev/keyring/packages/chain": 13 | version "0.2.0" 14 | resolved "file:packages/chain" 15 | dependencies: 16 | "@keyring/util" "^0.2.0" 17 | ramda "^0.26.1" 18 | 19 | "@keyring/plugin@^0.2.0", "@keyring/plugin@file:/Users/alex/dev/keyring/packages/plugin": 20 | version "0.2.0" 21 | resolved "file:packages/plugin" 22 | dependencies: 23 | "@keyring/util" "^0.2.0" 24 | 25 | "@keyring/transaction@^0.2.2", "@keyring/transaction@file:/Users/alex/dev/keyring/packages/transaction": 26 | version "0.2.2" 27 | resolved "file:packages/transaction" 28 | dependencies: 29 | "@keyring/chain" "^0.2.0" 30 | "@keyring/plugin" "^0.2.0" 31 | "@keyring/util" "^0.2.0" 32 | ecc-tools "^1.0.14" 33 | 34 | "@keyring/util@^0.2.0", "@keyring/util@file:/Users/alex/dev/keyring/packages/util": 35 | version "0.2.0" 36 | resolved "file:packages/util" 37 | dependencies: 38 | bn.js "^4.11.8" 39 | bs58check "^2.1.2" 40 | ramda "^0.26.1" 41 | 42 | ansi-colors@3.2.3: 43 | version "3.2.3" 44 | resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz" 45 | 46 | ansi-regex@^2.0.0: 47 | version "2.1.1" 48 | resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz" 49 | 50 | ansi-regex@^3.0.0: 51 | version "3.0.0" 52 | resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz" 53 | 54 | ansi-regex@^4.1.0: 55 | version "4.1.0" 56 | resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz" 57 | 58 | ansi-styles@^3.2.1: 59 | version "3.2.1" 60 | resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" 61 | dependencies: 62 | color-convert "^1.9.0" 63 | 64 | argparse@^1.0.7: 65 | version "1.0.10" 66 | resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" 67 | dependencies: 68 | sprintf-js "~1.0.2" 69 | 70 | assertion-error@^1.1.0: 71 | version "1.1.0" 72 | resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz" 73 | 74 | balanced-match@^1.0.0: 75 | version "1.0.0" 76 | resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz" 77 | 78 | base-x@^3.0.2: 79 | version "3.0.5" 80 | resolved "https://registry.npmjs.org/base-x/-/base-x-3.0.5.tgz" 81 | dependencies: 82 | safe-buffer "^5.0.1" 83 | 84 | bindings@^1.2.1: 85 | version "1.4.0" 86 | resolved "https://registry.npmjs.org/bindings/-/bindings-1.4.0.tgz" 87 | dependencies: 88 | file-uri-to-path "1.0.0" 89 | 90 | bip66@^1.1.3: 91 | version "1.1.5" 92 | resolved "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz" 93 | dependencies: 94 | safe-buffer "^5.0.1" 95 | 96 | bn.js@^4.11.3, bn.js@^4.11.8, bn.js@^4.4.0: 97 | version "4.11.8" 98 | resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz" 99 | 100 | brace-expansion@^1.1.7: 101 | version "1.1.11" 102 | resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" 103 | dependencies: 104 | balanced-match "^1.0.0" 105 | concat-map "0.0.1" 106 | 107 | brorand@^1.0.1: 108 | version "1.1.0" 109 | resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz" 110 | 111 | browser-stdout@1.3.1: 112 | version "1.3.1" 113 | resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz" 114 | 115 | browserify-aes@^1.0.6: 116 | version "1.2.0" 117 | resolved "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz" 118 | dependencies: 119 | buffer-xor "^1.0.3" 120 | cipher-base "^1.0.0" 121 | create-hash "^1.1.0" 122 | evp_bytestokey "^1.0.3" 123 | inherits "^2.0.1" 124 | safe-buffer "^5.0.1" 125 | 126 | bs58@^4.0.0, bs58@^4.0.1: 127 | version "4.0.1" 128 | resolved "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz" 129 | dependencies: 130 | base-x "^3.0.2" 131 | 132 | bs58check@^2.0.2, bs58check@^2.1.2: 133 | version "2.1.2" 134 | resolved "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz" 135 | dependencies: 136 | bs58 "^4.0.0" 137 | create-hash "^1.1.0" 138 | safe-buffer "^5.1.2" 139 | 140 | buffer-xor@^1.0.3: 141 | version "1.0.3" 142 | resolved "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz" 143 | 144 | camelcase@^5.0.0: 145 | version "5.3.1" 146 | resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" 147 | integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== 148 | 149 | chai-bignumber@^3.0.0: 150 | version "3.0.0" 151 | resolved "https://registry.npmjs.org/chai-bignumber/-/chai-bignumber-3.0.0.tgz" 152 | 153 | chai@^4.2.0: 154 | version "4.2.0" 155 | resolved "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz" 156 | dependencies: 157 | assertion-error "^1.1.0" 158 | check-error "^1.0.2" 159 | deep-eql "^3.0.1" 160 | get-func-name "^2.0.0" 161 | pathval "^1.1.0" 162 | type-detect "^4.0.5" 163 | 164 | chalk@^2.0.1: 165 | version "2.4.2" 166 | resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" 167 | dependencies: 168 | ansi-styles "^3.2.1" 169 | escape-string-regexp "^1.0.5" 170 | supports-color "^5.3.0" 171 | 172 | check-error@^1.0.2: 173 | version "1.0.2" 174 | resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz" 175 | 176 | cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: 177 | version "1.0.4" 178 | resolved "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz" 179 | dependencies: 180 | inherits "^2.0.1" 181 | safe-buffer "^5.0.1" 182 | 183 | cliui@^4.0.0: 184 | version "4.1.0" 185 | resolved "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz" 186 | dependencies: 187 | string-width "^2.1.1" 188 | strip-ansi "^4.0.0" 189 | wrap-ansi "^2.0.0" 190 | 191 | code-point-at@^1.0.0: 192 | version "1.1.0" 193 | resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz" 194 | 195 | color-convert@^1.9.0: 196 | version "1.9.3" 197 | resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" 198 | dependencies: 199 | color-name "1.1.3" 200 | 201 | color-name@1.1.3: 202 | version "1.1.3" 203 | resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" 204 | 205 | commander@~2.20.3: 206 | version "2.20.3" 207 | resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" 208 | 209 | commander@2.15.1: 210 | version "2.15.1" 211 | resolved "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz" 212 | 213 | concat-map@0.0.1: 214 | version "0.0.1" 215 | resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" 216 | 217 | create-hash@^1.1.0, create-hash@^1.1.2: 218 | version "1.2.0" 219 | resolved "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz" 220 | dependencies: 221 | cipher-base "^1.0.1" 222 | inherits "^2.0.1" 223 | md5.js "^1.3.4" 224 | ripemd160 "^2.0.1" 225 | sha.js "^2.4.0" 226 | 227 | create-hmac@^1.1.4: 228 | version "1.1.7" 229 | resolved "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz" 230 | dependencies: 231 | cipher-base "^1.0.3" 232 | create-hash "^1.1.0" 233 | inherits "^2.0.1" 234 | ripemd160 "^2.0.0" 235 | safe-buffer "^5.0.1" 236 | sha.js "^2.4.8" 237 | 238 | cross-spawn@^6.0.0: 239 | version "6.0.5" 240 | resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz" 241 | dependencies: 242 | nice-try "^1.0.4" 243 | path-key "^2.0.1" 244 | semver "^5.5.0" 245 | shebang-command "^1.2.0" 246 | which "^1.2.9" 247 | 248 | debug@3.1.0: 249 | version "3.1.0" 250 | resolved "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz" 251 | integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== 252 | dependencies: 253 | ms "2.0.0" 254 | 255 | debug@3.2.6: 256 | version "3.2.6" 257 | resolved "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz" 258 | dependencies: 259 | ms "^2.1.1" 260 | 261 | decamelize@^1.2.0: 262 | version "1.2.0" 263 | resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" 264 | 265 | deep-eql@^3.0.1: 266 | version "3.0.1" 267 | resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz" 268 | dependencies: 269 | type-detect "^4.0.0" 270 | 271 | define-properties@^1.1.2: 272 | version "1.1.3" 273 | resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz" 274 | dependencies: 275 | object-keys "^1.0.12" 276 | 277 | diff@3.5.0: 278 | version "3.5.0" 279 | resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz" 280 | 281 | drbg.js@^1.0.1: 282 | version "1.0.1" 283 | resolved "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz" 284 | dependencies: 285 | browserify-aes "^1.0.6" 286 | create-hash "^1.1.2" 287 | create-hmac "^1.1.4" 288 | 289 | ecc-tools@^1.0.14: 290 | version "1.0.14" 291 | resolved "https://registry.npmjs.org/ecc-tools/-/ecc-tools-1.0.14.tgz" 292 | dependencies: 293 | bs58 "^4.0.1" 294 | bs58check "^2.0.2" 295 | es6-promise "^3.2.1" 296 | json-stable-stringify "^1.0.1" 297 | secp256k1 "^3.1.0" 298 | triplesec "^3.0.25" 299 | 300 | elliptic@^6.2.3: 301 | version "6.4.1" 302 | resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz" 303 | dependencies: 304 | bn.js "^4.4.0" 305 | brorand "^1.0.1" 306 | hash.js "^1.0.0" 307 | hmac-drbg "^1.0.0" 308 | inherits "^2.0.1" 309 | minimalistic-assert "^1.0.0" 310 | minimalistic-crypto-utils "^1.0.0" 311 | 312 | emoji-regex@^7.0.1: 313 | version "7.0.3" 314 | resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz" 315 | 316 | end-of-stream@^1.1.0: 317 | version "1.4.1" 318 | resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz" 319 | dependencies: 320 | once "^1.4.0" 321 | 322 | es-abstract@^1.5.1: 323 | version "1.13.0" 324 | resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz" 325 | dependencies: 326 | es-to-primitive "^1.2.0" 327 | function-bind "^1.1.1" 328 | has "^1.0.3" 329 | is-callable "^1.1.4" 330 | is-regex "^1.0.4" 331 | object-keys "^1.0.12" 332 | 333 | es-to-primitive@^1.2.0: 334 | version "1.2.0" 335 | resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz" 336 | dependencies: 337 | is-callable "^1.1.4" 338 | is-date-object "^1.0.1" 339 | is-symbol "^1.0.2" 340 | 341 | es6-promise@^3.2.1: 342 | version "3.3.1" 343 | resolved "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz" 344 | 345 | escape-string-regexp@^1.0.5, escape-string-regexp@1.0.5: 346 | version "1.0.5" 347 | resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" 348 | 349 | esprima@^4.0.0: 350 | version "4.0.1" 351 | resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" 352 | 353 | evp_bytestokey@^1.0.3: 354 | version "1.0.3" 355 | resolved "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz" 356 | dependencies: 357 | md5.js "^1.3.4" 358 | safe-buffer "^5.1.1" 359 | 360 | execa@^1.0.0: 361 | version "1.0.0" 362 | resolved "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz" 363 | dependencies: 364 | cross-spawn "^6.0.0" 365 | get-stream "^4.0.0" 366 | is-stream "^1.1.0" 367 | npm-run-path "^2.0.0" 368 | p-finally "^1.0.0" 369 | signal-exit "^3.0.0" 370 | strip-eof "^1.0.0" 371 | 372 | file-uri-to-path@1.0.0: 373 | version "1.0.0" 374 | resolved "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz" 375 | 376 | find-up@^3.0.0, find-up@3.0.0: 377 | version "3.0.0" 378 | resolved "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz" 379 | dependencies: 380 | locate-path "^3.0.0" 381 | 382 | flat@^4.1.0: 383 | version "4.1.0" 384 | resolved "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz" 385 | dependencies: 386 | is-buffer "~2.0.3" 387 | 388 | fs.realpath@^1.0.0: 389 | version "1.0.0" 390 | resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" 391 | 392 | function-bind@^1.1.1: 393 | version "1.1.2" 394 | resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" 395 | integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== 396 | 397 | get-caller-file@^1.0.1: 398 | version "1.0.3" 399 | resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz" 400 | 401 | get-caller-file@^2.0.1: 402 | version "2.0.5" 403 | resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" 404 | 405 | get-func-name@^2.0.0: 406 | version "2.0.0" 407 | resolved "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz" 408 | 409 | get-stream@^4.0.0: 410 | version "4.1.0" 411 | resolved "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz" 412 | dependencies: 413 | pump "^3.0.0" 414 | 415 | glob@7.1.2: 416 | version "7.1.2" 417 | resolved "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz" 418 | dependencies: 419 | fs.realpath "^1.0.0" 420 | inflight "^1.0.4" 421 | inherits "2" 422 | minimatch "^3.0.4" 423 | once "^1.3.0" 424 | path-is-absolute "^1.0.0" 425 | 426 | glob@7.1.3: 427 | version "7.1.3" 428 | resolved "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz" 429 | dependencies: 430 | fs.realpath "^1.0.0" 431 | inflight "^1.0.4" 432 | inherits "2" 433 | minimatch "^3.0.4" 434 | once "^1.3.0" 435 | path-is-absolute "^1.0.0" 436 | 437 | growl@1.10.5: 438 | version "1.10.5" 439 | resolved "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz" 440 | 441 | has-flag@^3.0.0: 442 | version "3.0.0" 443 | resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" 444 | 445 | has-symbols@^1.0.0: 446 | version "1.0.3" 447 | resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" 448 | integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== 449 | 450 | has@^1.0.1, has@^1.0.3: 451 | version "1.0.3" 452 | resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" 453 | dependencies: 454 | function-bind "^1.1.1" 455 | 456 | hash-base@^3.0.0: 457 | version "3.0.4" 458 | resolved "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz" 459 | dependencies: 460 | inherits "^2.0.1" 461 | safe-buffer "^5.0.1" 462 | 463 | hash.js@^1.0.0, hash.js@^1.0.3: 464 | version "1.1.7" 465 | resolved "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz" 466 | dependencies: 467 | inherits "^2.0.3" 468 | minimalistic-assert "^1.0.1" 469 | 470 | he@1.1.1: 471 | version "1.1.1" 472 | resolved "https://registry.npmjs.org/he/-/he-1.1.1.tgz" 473 | 474 | he@1.2.0: 475 | version "1.2.0" 476 | resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz" 477 | 478 | hmac-drbg@^1.0.0: 479 | version "1.0.1" 480 | resolved "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz" 481 | dependencies: 482 | hash.js "^1.0.3" 483 | minimalistic-assert "^1.0.0" 484 | minimalistic-crypto-utils "^1.0.1" 485 | 486 | iced-error@>=0.0.9: 487 | version "0.0.13" 488 | resolved "https://registry.npmjs.org/iced-error/-/iced-error-0.0.13.tgz" 489 | 490 | iced-lock@^1.0.1: 491 | version "1.1.0" 492 | resolved "https://registry.npmjs.org/iced-lock/-/iced-lock-1.1.0.tgz" 493 | dependencies: 494 | iced-runtime "^1.0.0" 495 | 496 | iced-runtime@^1.0.0, iced-runtime@^1.0.2, iced-runtime@>=0.0.1: 497 | version "1.0.3" 498 | resolved "https://registry.npmjs.org/iced-runtime/-/iced-runtime-1.0.3.tgz" 499 | 500 | inflight@^1.0.4: 501 | version "1.0.6" 502 | resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" 503 | dependencies: 504 | once "^1.3.0" 505 | wrappy "1" 506 | 507 | inherits@^2.0.1, inherits@^2.0.3, inherits@2: 508 | version "2.0.4" 509 | resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" 510 | 511 | invert-kv@^2.0.0: 512 | version "2.0.0" 513 | resolved "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz" 514 | 515 | is-buffer@~2.0.3: 516 | version "2.0.3" 517 | resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz" 518 | 519 | is-callable@^1.1.4: 520 | version "1.1.4" 521 | resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz" 522 | 523 | is-date-object@^1.0.1: 524 | version "1.0.1" 525 | resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz" 526 | 527 | is-fullwidth-code-point@^1.0.0: 528 | version "1.0.0" 529 | resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz" 530 | dependencies: 531 | number-is-nan "^1.0.0" 532 | 533 | is-fullwidth-code-point@^2.0.0: 534 | version "2.0.0" 535 | resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz" 536 | 537 | is-regex@^1.0.4: 538 | version "1.0.4" 539 | resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz" 540 | dependencies: 541 | has "^1.0.1" 542 | 543 | is-stream@^1.1.0: 544 | version "1.1.0" 545 | resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz" 546 | 547 | is-symbol@^1.0.2: 548 | version "1.0.2" 549 | resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz" 550 | dependencies: 551 | has-symbols "^1.0.0" 552 | 553 | isexe@^2.0.0: 554 | version "2.0.0" 555 | resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" 556 | 557 | js-yaml@3.13.1: 558 | version "3.13.1" 559 | resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz" 560 | dependencies: 561 | argparse "^1.0.7" 562 | esprima "^4.0.0" 563 | 564 | json-stable-stringify@^1.0.1: 565 | version "1.0.1" 566 | resolved "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz" 567 | dependencies: 568 | jsonify "~0.0.0" 569 | 570 | jsonify@~0.0.0: 571 | version "0.0.0" 572 | resolved "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz" 573 | 574 | lcid@^2.0.0: 575 | version "2.0.0" 576 | resolved "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz" 577 | dependencies: 578 | invert-kv "^2.0.0" 579 | 580 | locate-path@^3.0.0: 581 | version "3.0.0" 582 | resolved "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz" 583 | dependencies: 584 | p-locate "^3.0.0" 585 | path-exists "^3.0.0" 586 | 587 | lodash@^4.17.11: 588 | version "4.17.15" 589 | resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz" 590 | 591 | log-symbols@2.2.0: 592 | version "2.2.0" 593 | resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz" 594 | dependencies: 595 | chalk "^2.0.1" 596 | 597 | map-age-cleaner@^0.1.1: 598 | version "0.1.3" 599 | resolved "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz" 600 | dependencies: 601 | p-defer "^1.0.0" 602 | 603 | md5.js@^1.3.4: 604 | version "1.3.5" 605 | resolved "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz" 606 | dependencies: 607 | hash-base "^3.0.0" 608 | inherits "^2.0.1" 609 | safe-buffer "^5.1.2" 610 | 611 | mem@^4.0.0: 612 | version "4.1.0" 613 | resolved "https://registry.npmjs.org/mem/-/mem-4.1.0.tgz" 614 | dependencies: 615 | map-age-cleaner "^0.1.1" 616 | mimic-fn "^1.0.0" 617 | p-is-promise "^2.0.0" 618 | 619 | mimic-fn@^1.0.0: 620 | version "1.2.0" 621 | resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz" 622 | 623 | minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: 624 | version "1.0.1" 625 | resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz" 626 | 627 | minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: 628 | version "1.0.1" 629 | resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz" 630 | 631 | minimatch@^3.0.4, minimatch@3.0.4: 632 | version "3.0.4" 633 | resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz" 634 | dependencies: 635 | brace-expansion "^1.1.7" 636 | 637 | minimist@0.0.8: 638 | version "0.0.8" 639 | resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" 640 | 641 | mkdirp@0.5.1: 642 | version "0.5.1" 643 | resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz" 644 | dependencies: 645 | minimist "0.0.8" 646 | 647 | mocha@^5.2.0: 648 | version "5.2.0" 649 | resolved "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz" 650 | dependencies: 651 | browser-stdout "1.3.1" 652 | commander "2.15.1" 653 | debug "3.1.0" 654 | diff "3.5.0" 655 | escape-string-regexp "1.0.5" 656 | glob "7.1.2" 657 | growl "1.10.5" 658 | he "1.1.1" 659 | minimatch "3.0.4" 660 | mkdirp "0.5.1" 661 | supports-color "5.4.0" 662 | 663 | mocha@^6.1.4: 664 | version "6.1.4" 665 | resolved "https://registry.npmjs.org/mocha/-/mocha-6.1.4.tgz" 666 | dependencies: 667 | ansi-colors "3.2.3" 668 | browser-stdout "1.3.1" 669 | debug "3.2.6" 670 | diff "3.5.0" 671 | escape-string-regexp "1.0.5" 672 | find-up "3.0.0" 673 | glob "7.1.3" 674 | growl "1.10.5" 675 | he "1.2.0" 676 | js-yaml "3.13.1" 677 | log-symbols "2.2.0" 678 | minimatch "3.0.4" 679 | mkdirp "0.5.1" 680 | ms "2.1.1" 681 | node-environment-flags "1.0.5" 682 | object.assign "4.1.0" 683 | strip-json-comments "2.0.1" 684 | supports-color "6.0.0" 685 | which "1.3.1" 686 | wide-align "1.1.3" 687 | yargs "13.2.2" 688 | yargs-parser "13.0.0" 689 | yargs-unparser "1.5.0" 690 | 691 | more-entropy@>=0.0.7: 692 | version "0.0.7" 693 | resolved "https://registry.npmjs.org/more-entropy/-/more-entropy-0.0.7.tgz" 694 | dependencies: 695 | iced-runtime ">=0.0.1" 696 | 697 | ms@^2.1.1, ms@2.1.1: 698 | version "2.1.1" 699 | resolved "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz" 700 | 701 | ms@2.0.0: 702 | version "2.0.0" 703 | resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" 704 | 705 | nan@^2.2.1: 706 | version "2.12.1" 707 | resolved "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz" 708 | 709 | nice-try@^1.0.4: 710 | version "1.0.5" 711 | resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz" 712 | 713 | node-environment-flags@1.0.5: 714 | version "1.0.5" 715 | resolved "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz" 716 | dependencies: 717 | object.getownpropertydescriptors "^2.0.3" 718 | semver "^5.7.0" 719 | 720 | npm-run-path@^2.0.0: 721 | version "2.0.2" 722 | resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz" 723 | dependencies: 724 | path-key "^2.0.0" 725 | 726 | number-is-nan@^1.0.0: 727 | version "1.0.1" 728 | resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz" 729 | 730 | object-keys@^1.0.11, object-keys@^1.0.12: 731 | version "1.1.1" 732 | resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" 733 | 734 | object.assign@4.1.0: 735 | version "4.1.0" 736 | resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz" 737 | dependencies: 738 | define-properties "^1.1.2" 739 | function-bind "^1.1.1" 740 | has-symbols "^1.0.0" 741 | object-keys "^1.0.11" 742 | 743 | object.getownpropertydescriptors@^2.0.3: 744 | version "2.0.3" 745 | resolved "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz" 746 | dependencies: 747 | define-properties "^1.1.2" 748 | es-abstract "^1.5.1" 749 | 750 | once@^1.3.0, once@^1.3.1, once@^1.4.0: 751 | version "1.4.0" 752 | resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" 753 | dependencies: 754 | wrappy "1" 755 | 756 | os-locale@^3.0.0, os-locale@^3.1.0: 757 | version "3.1.0" 758 | resolved "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz" 759 | dependencies: 760 | execa "^1.0.0" 761 | lcid "^2.0.0" 762 | mem "^4.0.0" 763 | 764 | p-defer@^1.0.0: 765 | version "1.0.0" 766 | resolved "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz" 767 | 768 | p-finally@^1.0.0: 769 | version "1.0.0" 770 | resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz" 771 | 772 | p-is-promise@^2.0.0: 773 | version "2.0.0" 774 | resolved "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.0.0.tgz" 775 | 776 | p-limit@^2.0.0: 777 | version "2.3.0" 778 | resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" 779 | integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== 780 | dependencies: 781 | p-try "^2.0.0" 782 | 783 | p-locate@^3.0.0: 784 | version "3.0.0" 785 | resolved "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz" 786 | dependencies: 787 | p-limit "^2.0.0" 788 | 789 | p-try@^2.0.0: 790 | version "2.0.0" 791 | resolved "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz" 792 | 793 | path-exists@^3.0.0: 794 | version "3.0.0" 795 | resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz" 796 | 797 | path-is-absolute@^1.0.0: 798 | version "1.0.1" 799 | resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" 800 | 801 | path-key@^2.0.0, path-key@^2.0.1: 802 | version "2.0.1" 803 | resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz" 804 | 805 | pathval@^1.1.0: 806 | version "1.1.0" 807 | resolved "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz" 808 | 809 | progress@~1.1.2: 810 | version "1.1.8" 811 | resolved "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz" 812 | 813 | pump@^3.0.0: 814 | version "3.0.0" 815 | resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz" 816 | dependencies: 817 | end-of-stream "^1.1.0" 818 | once "^1.3.1" 819 | 820 | ramda@^0.26.1: 821 | version "0.26.1" 822 | resolved "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz" 823 | 824 | require-directory@^2.1.1: 825 | version "2.1.1" 826 | resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" 827 | 828 | require-main-filename@^1.0.1: 829 | version "1.0.1" 830 | resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz" 831 | 832 | require-main-filename@^2.0.0: 833 | version "2.0.0" 834 | resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz" 835 | 836 | ripemd160@^2.0.0, ripemd160@^2.0.1: 837 | version "2.0.2" 838 | resolved "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz" 839 | dependencies: 840 | hash-base "^3.0.0" 841 | inherits "^2.0.1" 842 | 843 | safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2: 844 | version "5.2.1" 845 | resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" 846 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 847 | 848 | secp256k1@^3.1.0: 849 | version "3.6.2" 850 | resolved "https://registry.npmjs.org/secp256k1/-/secp256k1-3.6.2.tgz" 851 | dependencies: 852 | bindings "^1.2.1" 853 | bip66 "^1.1.3" 854 | bn.js "^4.11.3" 855 | create-hash "^1.1.2" 856 | drbg.js "^1.0.1" 857 | elliptic "^6.2.3" 858 | nan "^2.2.1" 859 | safe-buffer "^5.1.0" 860 | 861 | semver@^5.5.0, semver@^5.7.0: 862 | version "5.7.0" 863 | resolved "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz" 864 | 865 | set-blocking@^2.0.0: 866 | version "2.0.0" 867 | resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" 868 | 869 | sha.js@^2.4.0, sha.js@^2.4.8: 870 | version "2.4.11" 871 | resolved "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz" 872 | dependencies: 873 | inherits "^2.0.1" 874 | safe-buffer "^5.0.1" 875 | 876 | shebang-command@^1.2.0: 877 | version "1.2.0" 878 | resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz" 879 | dependencies: 880 | shebang-regex "^1.0.0" 881 | 882 | shebang-regex@^1.0.0: 883 | version "1.0.0" 884 | resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz" 885 | 886 | signal-exit@^3.0.0: 887 | version "3.0.2" 888 | resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz" 889 | 890 | source-map@~0.6.1: 891 | version "0.6.1" 892 | resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" 893 | 894 | sprintf-js@~1.0.2: 895 | version "1.0.3" 896 | resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" 897 | 898 | string-width@^1.0.1: 899 | version "1.0.2" 900 | resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz" 901 | dependencies: 902 | code-point-at "^1.0.0" 903 | is-fullwidth-code-point "^1.0.0" 904 | strip-ansi "^3.0.0" 905 | 906 | "string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1: 907 | version "2.1.1" 908 | resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz" 909 | dependencies: 910 | is-fullwidth-code-point "^2.0.0" 911 | strip-ansi "^4.0.0" 912 | 913 | string-width@^3.0.0: 914 | version "3.1.0" 915 | resolved "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz" 916 | dependencies: 917 | emoji-regex "^7.0.1" 918 | is-fullwidth-code-point "^2.0.0" 919 | strip-ansi "^5.1.0" 920 | 921 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: 922 | version "3.0.1" 923 | resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" 924 | dependencies: 925 | ansi-regex "^2.0.0" 926 | 927 | strip-ansi@^4.0.0: 928 | version "4.0.0" 929 | resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz" 930 | dependencies: 931 | ansi-regex "^3.0.0" 932 | 933 | strip-ansi@^5.1.0: 934 | version "5.2.0" 935 | resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz" 936 | dependencies: 937 | ansi-regex "^4.1.0" 938 | 939 | strip-eof@^1.0.0: 940 | version "1.0.0" 941 | resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz" 942 | 943 | strip-json-comments@2.0.1: 944 | version "2.0.1" 945 | resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz" 946 | 947 | supports-color@^5.3.0: 948 | version "5.5.0" 949 | resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" 950 | dependencies: 951 | has-flag "^3.0.0" 952 | 953 | supports-color@5.4.0: 954 | version "5.4.0" 955 | resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz" 956 | dependencies: 957 | has-flag "^3.0.0" 958 | 959 | supports-color@6.0.0: 960 | version "6.0.0" 961 | resolved "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz" 962 | dependencies: 963 | has-flag "^3.0.0" 964 | 965 | triplesec@^3.0.25: 966 | version "3.0.27" 967 | resolved "https://registry.npmjs.org/triplesec/-/triplesec-3.0.27.tgz" 968 | dependencies: 969 | iced-error ">=0.0.9" 970 | iced-lock "^1.0.1" 971 | iced-runtime "^1.0.2" 972 | more-entropy ">=0.0.7" 973 | progress "~1.1.2" 974 | uglify-js "^3.1.9" 975 | 976 | type-detect@^4.0.0, type-detect@^4.0.5: 977 | version "4.0.8" 978 | resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" 979 | 980 | uglify-js@^3.1.9: 981 | version "3.7.3" 982 | resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.3.tgz" 983 | dependencies: 984 | commander "~2.20.3" 985 | source-map "~0.6.1" 986 | 987 | which-module@^2.0.0: 988 | version "2.0.0" 989 | resolved "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz" 990 | 991 | which@^1.2.9, which@1.3.1: 992 | version "1.3.1" 993 | resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz" 994 | dependencies: 995 | isexe "^2.0.0" 996 | 997 | wide-align@1.1.3: 998 | version "1.1.3" 999 | resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz" 1000 | dependencies: 1001 | string-width "^1.0.2 || 2" 1002 | 1003 | wrap-ansi@^2.0.0: 1004 | version "2.1.0" 1005 | resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz" 1006 | dependencies: 1007 | string-width "^1.0.1" 1008 | strip-ansi "^3.0.1" 1009 | 1010 | wrappy@1: 1011 | version "1.0.2" 1012 | resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" 1013 | 1014 | "y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: 1015 | version "4.0.0" 1016 | resolved "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz" 1017 | 1018 | yargs-parser@^11.1.1: 1019 | version "11.1.1" 1020 | resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz" 1021 | dependencies: 1022 | camelcase "^5.0.0" 1023 | decamelize "^1.2.0" 1024 | 1025 | yargs-parser@^13.0.0, yargs-parser@13.0.0: 1026 | version "13.0.0" 1027 | resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.0.0.tgz" 1028 | dependencies: 1029 | camelcase "^5.0.0" 1030 | decamelize "^1.2.0" 1031 | 1032 | yargs-unparser@1.5.0: 1033 | version "1.5.0" 1034 | resolved "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz" 1035 | dependencies: 1036 | flat "^4.1.0" 1037 | lodash "^4.17.11" 1038 | yargs "^12.0.5" 1039 | 1040 | yargs@^12.0.5: 1041 | version "12.0.5" 1042 | resolved "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz" 1043 | dependencies: 1044 | cliui "^4.0.0" 1045 | decamelize "^1.2.0" 1046 | find-up "^3.0.0" 1047 | get-caller-file "^1.0.1" 1048 | os-locale "^3.0.0" 1049 | require-directory "^2.1.1" 1050 | require-main-filename "^1.0.1" 1051 | set-blocking "^2.0.0" 1052 | string-width "^2.0.0" 1053 | which-module "^2.0.0" 1054 | y18n "^3.2.1 || ^4.0.0" 1055 | yargs-parser "^11.1.1" 1056 | 1057 | yargs@13.2.2: 1058 | version "13.2.2" 1059 | resolved "https://registry.npmjs.org/yargs/-/yargs-13.2.2.tgz" 1060 | dependencies: 1061 | cliui "^4.0.0" 1062 | find-up "^3.0.0" 1063 | get-caller-file "^2.0.1" 1064 | os-locale "^3.1.0" 1065 | require-directory "^2.1.1" 1066 | require-main-filename "^2.0.0" 1067 | set-blocking "^2.0.0" 1068 | string-width "^3.0.0" 1069 | which-module "^2.0.0" 1070 | y18n "^4.0.0" 1071 | yargs-parser "^13.0.0" 1072 | --------------------------------------------------------------------------------