├── .editorconfig
├── .github
└── workflows
│ └── nodejs.yml
├── .gitignore
├── .tool-versions
├── .yarn
└── releases
│ └── yarn-3.2.0.cjs
├── .yarnrc.yml
├── LICENSE
├── README.md
├── build.js
├── media
└── txforge-poster.jpg
├── package.json
├── src
├── casts
│ ├── index.js
│ ├── op-return.js
│ ├── p2ms.js
│ ├── p2pk.js
│ ├── p2pkh.js
│ ├── p2rph.js
│ └── raw.js
├── classes
│ ├── cast.js
│ ├── forge.js
│ ├── shared.js
│ ├── tape.js
│ └── utxo.js
├── extra
│ └── r-puzzle.js
├── helpers
│ ├── asm.js
│ ├── index.js
│ └── num.js
├── index.js
└── macros
│ ├── binary.js
│ ├── index.js
│ ├── push-tx.js
│ ├── sign-tx.js
│ └── varint.js
├── test
├── casts
│ ├── opreturn.test.js
│ ├── p2ms.test.js
│ ├── p2pk.test.js
│ ├── p2pkh.test.js
│ ├── p2rph.test.js
│ └── raw.test.js
├── classes
│ ├── cast.test.js
│ ├── forge.test.js
│ ├── shared.test.js
│ ├── tape.test.js
│ └── utxo.test.js
├── extra
│ └── r-puzzle.test.js
├── helpers
│ ├── asm.test.js
│ └── num.test.js
├── macros
│ ├── binary.test.js
│ ├── push-tx.test.js
│ └── varint.test.js
└── vectors
│ └── bip69.json
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | insert_final_newline = true
6 |
7 | [*.{js,json,yml}]
8 | charset = utf-8
9 | indent_style = space
10 | indent_size = 2
11 |
--------------------------------------------------------------------------------
/.github/workflows/nodejs.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 |
4 | name: Node.js CI
5 |
6 | on:
7 | push:
8 | branches: [ master ]
9 | pull_request:
10 | branches: [ master ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | strategy:
18 | matrix:
19 | node-version: [12.x, 14.x, 16.x, 18.x]
20 |
21 | steps:
22 | - uses: actions/checkout@v2
23 | - name: Use Node.js ${{ matrix.node-version }}
24 | uses: actions/setup-node@v1
25 | with:
26 | node-version: ${{ matrix.node-version }}
27 | - run: yarn install
28 | - run: yarn run test
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | .pnp.*
4 | .yarn/*
5 | !.yarn/patches
6 | !.yarn/plugins
7 | !.yarn/releases
8 | !.yarn/sdks
9 | !.yarn/versions
10 |
11 | dist
12 | node_modules
13 | test/demo*.js
14 |
--------------------------------------------------------------------------------
/.tool-versions:
--------------------------------------------------------------------------------
1 | nodejs lts-gallium
--------------------------------------------------------------------------------
/.yarnrc.yml:
--------------------------------------------------------------------------------
1 | nodeLinker: node-modules
2 | yarnPath: .yarn/releases/yarn-3.2.0.cjs
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TxForge
2 |
3 | 
4 |
5 | [](https://www.npmjs.com/package/txforge)
6 | 
7 | 
8 |
9 |
10 | TxForge is an industrial strength transaction builder. Re-built on top of [nimble](https://github.com/runonbitcoin/nimble), TxForge 2.0 is an ultra-lightweight, ultra-flexible, essential part of any respectable Bitcoin builders' toolkit.
11 |
12 | - simple, human-friendly declarative API for composing transactions
13 | - extendable and flexible - can forge transactions with any script template imaginable
14 | - under the hood it's powered by nimble, less that 1/5 the size of [moneybutton/bsv v2](https://github.com/moneybutton/bsv) and up to 4 times as fast!
15 | - a robust library using well-tested, modern javascript
16 |
17 | *The legacy version of TxForge, powered by [bsv v2](https://github.com/moneybutton/bsv), can be found on the [legacy branch](https://github.com/libitx/txforge/tree/legacy).*
18 |
19 | ## Sponsors
20 |
21 |
Supported by:
22 |
23 |
24 |
25 |
26 |
27 |
28 | Your sponsorship will help us continue to release and maintain software that Bitcoin businesses and developers depend on.
29 |
30 | #### 👉 [Sponsor Chronos Labs' open source work](https://www.chronoslabs.net/sponsor/)
31 |
32 | ## Upgrading
33 |
34 | If you've used previous versions of TxForge, conceptually everything is the same. However, v2.0 is a rewrite from top to bottom, powered by a new Bitcoin library, and incorporates some API changes, most notably with how Casts are defined and used.
35 |
36 | Full more details, check out the [TxForge 2 upgrade notes](https://github.com/libitx/txforge/wiki/Installing-and-upgrading-TxForge#txforge-2-upgrade-notes).
37 |
38 | ## Quick start
39 |
40 | Install TxForge with `npm` or `yarn`:
41 |
42 | ```shell
43 | npm install txforge
44 | # or
45 | yarn add txforge
46 | ```
47 |
48 | Alternatively use in a browser via CDN:
49 |
50 | ```html
51 |
52 |
53 |
54 |
55 |
56 | ```
57 |
58 | Grab your tools and put on your safety googles. Lets forge a transaction... it's hammer time!
59 |
60 | ```js
61 | import { forgeTx, toUTXO, casts } from 'txforge'
62 |
63 | // We'll use these Casts in our transaction
64 | const { P2PKH, OpReturn } = casts
65 |
66 | // You'll need UTXOs to fund a transaction. Use the `toUTXO` helper to turn
67 | // your UTXO data into the required objects.
68 | const utxo = toUTXO({
69 | txid, // utxo transaction id
70 | vout, // utxo output index
71 | satoshis, // utxo amount
72 | script // utxo lock script
73 | })
74 |
75 | // Forge a transaction
76 | const tx = forgeTx({
77 | inputs: [
78 | P2PKH.unlock(utxo, { privkey: myPrivateKey })
79 | ],
80 | outputs: [
81 | P2PKH.lock(5000, { address: '1DBz6V6CmvjZTvfjvWpvvwuM1X7GkRmWEq' }),
82 | OpReturn.lock(0, { data: ['meta', '1DBz6V6CmvjZTvfjvWpvvwuM1X7GkRmWEq', txid] })
83 | ],
84 | change: { address: '1Nro9WkpaKm9axmcfPVp79dAJU1Gx7VmMZ' }
85 | })
86 |
87 | // And behold! Forged by the Gods and found by a King - a transaction is born.
88 | console.log(tx.toHex())
89 | ```
90 |
91 | And that's it. Really. One function that returns a fully built and signed transaction, ready to send off to your favourite transaction processor.
92 |
93 | But there's more, much more. When you're ready, grab a coffee and dive into the following to discover how TxForge can be used to lock and unlock any combination of script template you can imagine.
94 |
95 | - [Understanding Casts](https://github.com/libitx/txforge/wiki/Understanding-Casts)
96 | - [Creating custom Casts](https://github.com/libitx/txforge/wiki/Creating-custom-Casts)
97 | - [Building Scripts with TxForge](https://github.com/libitx/txforge/wiki/Building-scripts-with-the-Tape-API)
98 |
99 | ## License
100 |
101 | TxForge is open source and released under the [Apache-2 License](https://github.com/libitx/txforge/blob/master/LICENSE).
102 |
103 | Copyright (c) 2020-2022 Chronos Labs Ltd.
104 |
--------------------------------------------------------------------------------
/build.js:
--------------------------------------------------------------------------------
1 | import esbuild from 'esbuild'
2 | import GlobalsPlugin from 'esbuild-plugin-globals'
3 |
4 | const makeAllPackagesExternalPlugin = {
5 | name: 'make-all-packages-external',
6 | setup(build) {
7 | let filter = /^[^.\/]|^\.[^.\/]|^\.\.[^\/]/ // Must not start with "/" or "./" or "../"
8 | build.onResolve({ filter }, args => ({ path: args.path, external: true }))
9 | },
10 | }
11 |
12 | esbuild.build({
13 | entryPoints: ['src/index.js'],
14 | outfile: 'dist/txforge.min.js',
15 | globalName: 'txforge',
16 | bundle: true,
17 | format: 'iife',
18 | platform: 'browser',
19 | target: 'es6',
20 | minify: true,
21 | keepNames: true,
22 | sourcemap: true,
23 | define: {
24 | VARIANT: 'browser'
25 | },
26 | plugins: [
27 | GlobalsPlugin({
28 | 'crypto': 'null',
29 | '@runonbitcoin/nimble': 'nimble'
30 | })
31 | ]
32 | })
33 |
34 | esbuild.build({
35 | entryPoints: ['src/index.js'],
36 | outfile: 'dist/txforge.bundled.min.js',
37 | globalName: 'txforge',
38 | bundle: true,
39 | format: 'iife',
40 | platform: 'browser',
41 | target: 'es6',
42 | minify: true,
43 | keepNames: true,
44 | sourcemap: true,
45 | define: {
46 | VARIANT: 'browser'
47 | },
48 | plugins: [
49 | GlobalsPlugin({
50 | 'crypto': 'null'
51 | })
52 | ]
53 | })
54 |
55 | esbuild.build({
56 | entryPoints: [
57 | 'src/index.js',
58 | 'src/extra/r-puzzle.js'
59 | ],
60 | outdir: 'dist/cjs',
61 | outExtension: {
62 | '.js': '.cjs'
63 | },
64 | bundle: true,
65 | format: 'cjs',
66 | platform: 'node',
67 | target: 'node10',
68 | keepNames: true,
69 | plugins: [
70 | makeAllPackagesExternalPlugin
71 | ]
72 | })
73 |
--------------------------------------------------------------------------------
/media/txforge-poster.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libitx/txforge/9e94780871286d0c9653170204b7b5eaeea4f61a/media/txforge-poster.jpg
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "txforge",
3 | "version": "2.1.0",
4 | "description": "Modern Bitcoin transaction builder, capable of supporting any non-standard and custom script type.",
5 | "keywords": [
6 | "bitcoin",
7 | "bsv",
8 | "transaction",
9 | "builder",
10 | "nimble"
11 | ],
12 | "author": "libitx",
13 | "license": "Apache-2.0",
14 | "repository": "https://github.com/libitx/txforge",
15 | "type": "module",
16 | "exports": {
17 | ".": {
18 | "require": "./dist/cjs/index.cjs",
19 | "import": "./src/index.js"
20 | },
21 | "./*": {
22 | "require": "./dist/cjs/*.cjs",
23 | "import": "./src/*.js"
24 | }
25 | },
26 | "main": "./dist/cjs/index.cjs",
27 | "browser": "./dist/txforge.min.js",
28 | "unpkg": "./dist/txforge.min.js",
29 | "files": [
30 | "dist",
31 | "src"
32 | ],
33 | "packageManager": "yarn@3.2.0",
34 | "scripts": {
35 | "build": "yarn clean && node build.js",
36 | "clean": "rm -rf dist",
37 | "test": "ava test/**/*.test.js"
38 | },
39 | "dependencies": {
40 | "@runonbitcoin/nimble": "^1.0.13"
41 | },
42 | "devDependencies": {
43 | "ava": "^4.2.0",
44 | "esbuild": "^0.14.38",
45 | "esbuild-plugin-globals": "^0.1.1"
46 | },
47 | "ava": {
48 | "concurrency": 4
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/casts/index.js:
--------------------------------------------------------------------------------
1 | export { OpReturn } from './op-return.js'
2 | export { P2MS } from './p2ms.js'
3 | export { P2PK } from './p2pk.js'
4 | export { P2PKH } from './p2pkh.js'
5 | export { P2RPH } from './p2rph.js'
6 | export { Raw } from './raw.js'
7 |
--------------------------------------------------------------------------------
/src/casts/op-return.js:
--------------------------------------------------------------------------------
1 | import nimble from '@runonbitcoin/nimble'
2 | import { Cast } from '../classes/cast.js'
3 |
4 | const { OP_FALSE, OP_RETURN } = nimble.constants.opcodes
5 |
6 | /**
7 | * OP_RETURN outputs are frequently used for publishing arbitrary data on-chain.
8 | *
9 | * As this is generally used for creating unspendable outputs, no unlocking
10 | * script is defined on this contract.
11 | *
12 | * ## Lock params
13 | *
14 | * - `data` - A single buffer or string, or array of buffers/strings.
15 | *
16 | * ## Examples
17 | *
18 | * ```
19 | * OpReturn.lock(0, { data: 'hello world' })
20 | *
21 | * OpReturn.lock(0, { data: ['hello', 'world'] })
22 | * ```
23 | */
24 | export class OpReturn extends Cast {
25 | lockingScript({ data }) {
26 | this.script
27 | .push(OP_FALSE)
28 | .push(OP_RETURN)
29 | .push(data)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/casts/p2ms.js:
--------------------------------------------------------------------------------
1 | import nimble from '@runonbitcoin/nimble'
2 | import { Cast } from '../classes/cast.js'
3 | import { num } from '../helpers/index.js'
4 | import { signTx } from '../macros/index.js'
5 |
6 | const { OP_0, OP_CHECKMULTISIG } = nimble.constants.opcodes
7 |
8 | /**
9 | * Pay to Multi Sig
10 | *
11 | * P2MS scripts are used to lock Bitcoin to multiple public keys. The Bitcoin
12 | * can later be unlocked by signing with the specified threshold of
13 | * corresponding private keys.
14 | *
15 | * ## Lock params
16 | *
17 | * - `pubkeys` - Array of public keys
18 | * - `threshold` - Integer of required signatures
19 | *
20 | * ## Unlock params
21 | *
22 | * - `privkeys` - Array of private keys
23 | *
24 | * ## Example
25 | *
26 | * ```
27 | * P2MS.lock(1000, { pubkeys: [pub1, pub2, pub3], threshold: 2 })
28 | *
29 | * P2MS.unlock(utxo, { privkey: [priv1, priv2] })
30 | * ```
31 | */
32 | export class P2MS extends Cast {
33 | init() {
34 | if (this.mode === 'lock') validateLock(this.params)
35 | if (this.mode === 'unlock') validateUnlock(this.params)
36 | }
37 |
38 | lockingScript({ pubkeys, threshold }) {
39 | this.script
40 | .push(num(threshold))
41 | .apply(pushPubkeys, [pubkeys])
42 | .push(num(pubkeys.length))
43 | .push(OP_CHECKMULTISIG)
44 | }
45 |
46 | unlockingScript({ privkeys }) {
47 | this.script
48 | .push(OP_0)
49 | .apply(pushSigs, [privkeys])
50 | }
51 | }
52 |
53 | function pushPubkeys(pubkeys) {
54 | pubkeys.forEach(pubkey => {
55 | this.script.push(pubkey)
56 | })
57 | }
58 |
59 | function pushSigs(privkeys) {
60 | privkeys.forEach(privkey => {
61 | this.script.apply(signTx, [privkey])
62 | })
63 | }
64 |
65 | function validateLock({ pubkeys, threshold } = {}) {
66 | if (!(Array.isArray(pubkeys) && pubkeys.every(k => k.point))) {
67 | throw new Error('P2MS lock must be created with array of `pubkeys`')
68 | }
69 |
70 | if (!Number.isInteger(threshold)) {
71 | throw new Error('P2MS lock must be created with `threshold` integer')
72 | }
73 | }
74 |
75 | function validateUnlock({ privkeys } = {}) {
76 | if (!(Array.isArray(privkeys) && privkeys.every(k => typeof k.toPublicKey === 'function'))) {
77 | throw new Error('P2MS unlock must be created with array of `privkeys`')
78 | }
79 | }
--------------------------------------------------------------------------------
/src/casts/p2pk.js:
--------------------------------------------------------------------------------
1 | import nimble from '@runonbitcoin/nimble'
2 | import { Cast } from '../classes/cast.js'
3 | import { signTx } from '../macros/index.js'
4 |
5 | const { OP_CHECKSIG } = nimble.constants.opcodes
6 |
7 | /**
8 | * Pay to Public Key
9 | *
10 | * P2PK scripts are used to lock Bitcoin to a public key. The Bitcoin can later
11 | * be unlocked using the corresponding private key.
12 | *
13 | * ## Lock params
14 | *
15 | * - `pubkey` - Public key
16 | *
17 | * ## Unlock params
18 | *
19 | * - `privkey` - Private key
20 | *
21 | * ## Examples
22 | *
23 | * ```
24 | * P2PK.lock(1000, { pubkey })
25 | *
26 | * P2PK.unlock(utxo, { privkey })
27 | * ```
28 | */
29 | export class P2PK extends Cast {
30 | init() {
31 | if (this.mode === 'lock') validateLock(this.params)
32 | if (this.mode === 'unlock') validateUnlock(this.params)
33 | }
34 |
35 | lockingScript({ pubkey }) {
36 | this.script
37 | .push(pubkey)
38 | .push(OP_CHECKSIG)
39 | }
40 |
41 | unlockingScript({ privkey }) {
42 | this.script.apply(signTx, [privkey])
43 | }
44 | }
45 |
46 | function validateLock({ pubkey } = {}) {
47 | if (!(pubkey && pubkey.point)) {
48 | throw new Error('P2PK unlock must be created with valid `pubkey`')
49 | }
50 | }
51 |
52 | function validateUnlock({ privkey } = {}) {
53 | if (!(privkey && typeof privkey.toPublicKey === 'function')) {
54 | throw new Error('P2PK unlock must be created with valid `privkey`')
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/casts/p2pkh.js:
--------------------------------------------------------------------------------
1 | import nimble from '@runonbitcoin/nimble'
2 | import { Cast } from '../classes/cast.js'
3 | import { signTx } from '../macros/index.js'
4 |
5 | const { Address } = nimble.classes
6 | const { OP_DUP, OP_HASH160, OP_EQUALVERIFY, OP_CHECKSIG } = nimble.constants.opcodes
7 |
8 | /**
9 | * Pay to Public Key Hash
10 | *
11 | * P2PKH scripts are used to lock Bitcoin to an address. The Bitcoin can later
12 | * be unlocked using the private key corresponding to the address.
13 | *
14 | * ## Lock params
15 | *
16 | * - `address` - address instance or string
17 | *
18 | * ## Unlock params
19 | *
20 | * - `privkey` - Private key
21 | *
22 | * ## Examples
23 | *
24 | * ```
25 | * P2PKH.lock(1000, { address })
26 | *
27 | * P2PKH.unlock(utxo, { privkey })
28 | * ```
29 | */
30 | export class P2PKH extends Cast {
31 | init(params) {
32 | if (typeof params.address === 'string') {
33 | this.params.address = Address.from(params.address)
34 | }
35 |
36 | if (this.mode === 'lock') validateLock(this.params)
37 | if (this.mode === 'unlock') validateUnlock(this.params)
38 | }
39 |
40 | lockingScript({ address }) {
41 | this.script
42 | .push(OP_DUP)
43 | .push(OP_HASH160)
44 | .push(address.pubkeyhash)
45 | .push(OP_EQUALVERIFY)
46 | .push(OP_CHECKSIG)
47 | }
48 |
49 | unlockingScript({ privkey }) {
50 | this.script
51 | .apply(signTx, [privkey])
52 | .push(privkey.toPublicKey())
53 | }
54 | }
55 |
56 | function validateLock({ address } = {}) {
57 | if (!(address && address.pubkeyhash)) {
58 | throw new Error('P2PKH lock must be created with valid `address`')
59 | }
60 | }
61 |
62 | function validateUnlock({ privkey } = {}) {
63 | if (!(privkey && typeof privkey.toPublicKey === 'function')) {
64 | throw new Error('P2PKH unlock must be created with valid `privkey`')
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/casts/p2rph.js:
--------------------------------------------------------------------------------
1 | import nimble from '@runonbitcoin/nimble'
2 | import { Cast } from '../classes/cast.js'
3 | import { asm } from '../helpers/index.js'
4 | import { signTx, signTxWithK } from '../macros/index.js'
5 |
6 | const { PrivateKey } = nimble.classes
7 | const { isBuffer, generatePrivateKey, sha256ripemd160 } = nimble.functions
8 |
9 | /**
10 | * Pay to R-Puzzle Hash
11 | *
12 | * P2RPH scripts are used to lock Bitcoin to a hash puzzle based on the R value
13 | * of an ECDSA signature. The Bitcoin can later be unlocked with knowledge of
14 | * the corresponding K value used in that signature.
15 | *
16 | * The technique allows for the spending party to sign the unlocking script
17 | * using any private key.
18 | *
19 | * ## Lock params
20 | *
21 | * - `r` - R value
22 | *
23 | * ## Unlock params
24 | *
25 | * - `k` - K value
26 | * - `privkey` - Optional private key to sign with
27 | *
28 | * ## Examples
29 | *
30 | * TxForge offers an additional module with helpers to generate K and R values.
31 | *
32 | * ```
33 | * import { generateK, calculateR } from 'txforge/extra/r-puzzle
34 | *
35 | * const k = generateK()
36 | * const r = calculateR(k)
37 | *
38 | * P2RPH.lock(1000, { r })
39 | *
40 | * P2RPH.unlock(utxo, { k })
41 | * ```
42 | */
43 | export class P2RPH extends Cast {
44 | init(params) {
45 | if (this.mode === 'unlock' && typeof params.privkey === 'undefined') {
46 | this.params.privkey = PrivateKey.fromRandom()
47 | }
48 |
49 | if (this.mode === 'lock') validateLock(this.params)
50 | if (this.mode === 'unlock') validateUnlock(this.params)
51 | }
52 |
53 | lockingScript({ r }) {
54 | this.script
55 | .push(asm('OP_OVER OP_3 OP_SPLIT OP_NIP OP_1 OP_SPLIT OP_SWAP OP_SPLIT OP_DROP OP_HASH160'))
56 | .push(sha256ripemd160(r))
57 | .push(asm('OP_EQUALVERIFY OP_TUCK OP_CHECKSIGVERIFY OP_CHECKSIG'))
58 | }
59 |
60 | unlockingScript({ k, privkey }) {
61 | this.script
62 | .apply(signTx, [privkey])
63 | .apply(signTxWithK, [privkey, k])
64 | .push(privkey.toPublicKey())
65 | }
66 | }
67 |
68 | function validateLock({ r } = {}) {
69 | if (!isBuffer(r) || ![32, 33].includes(r.length)) {
70 | throw new Error('P2RPH lock must be created with valid `r` buffer')
71 | }
72 | }
73 |
74 | function validateUnlock({ k } = {}) {
75 | if (!isBuffer(k) || k.length !== 32) {
76 | throw new Error('P2RPH unlock must be created with valid `k` buffer')
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/casts/raw.js:
--------------------------------------------------------------------------------
1 | import nimble from '@runonbitcoin/nimble'
2 | import { Cast } from '../classes/cast.js'
3 |
4 | const { Script } = nimble.classes
5 |
6 | /**
7 | * The Raw cast provides a way to use an existing script with TxForge.
8 | *
9 | * * ## Lock params
10 | *
11 | * - `script` - Script instance or hex-encoded string
12 | *
13 | * ## Unlock params
14 | *
15 | * - `script` - Script instance or hex-encoded string
16 | *
17 | * ## Examples
18 | *
19 | * ```
20 | * Raw.lock(1000, { script: '76a91412ab8dc588ca9d5787dde7eb29569da63c3a238c88ac' })
21 | * ```
22 | */
23 | export class Raw extends Cast {
24 | init(params) {
25 | if (typeof params.script === 'string') {
26 | this.params.script = Script.fromString(params.script)
27 | }
28 |
29 | if (!(this.params.script && typeof this.params.script.toBuffer === 'function')) {
30 | throw new Error('Raw cast must be created with valid `script`')
31 | }
32 | }
33 |
34 | lockingScript({ script }) {
35 | this.script.push(script.chunks)
36 | }
37 |
38 | unlockingScript({ script }) {
39 | this.script.push(script.chunks)
40 | }
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/src/classes/cast.js:
--------------------------------------------------------------------------------
1 | import nimble from '@runonbitcoin/nimble'
2 | import { forgeTx } from './forge.js'
3 | import { Tape, toScript } from './tape.js'
4 | import { getUTXO } from './utxo.js'
5 | import { getOpt } from './shared.js'
6 |
7 | const { Transaction } = nimble.classes
8 | const { evalScript } = nimble.functions
9 |
10 | /**
11 | * Casts are Bitcoin script templates.
12 | *
13 | * A Bitcoin transaction consists of two sides: inputs and outputs.
14 | *
15 | * An output contains a locking script which locks a number of satoshis to a
16 | * puzzle. Inputs contain an unlocking script which provides the solution to a
17 | * previous output's puzzle.
18 | *
19 | * A class that extends from `Cast` defines both `lockingScript` and
20 | * `unlockingScript` functions, and so defines the puzzle coins are locked to
21 | * and the solution for unlocking and spending those coins again. Casts have a
22 | * simple API and it is trivial to add your own helpers and macros to create
23 | * more complex script templates.
24 | *
25 | * ## Defining a Cast
26 | *
27 | * The following example implements a simple hash puzzle where coins can be
28 | * locked to a secret and then unlocked with the same secret, without the secret
29 | * being revealed onchain.
30 | *
31 | * ```
32 | * import { Cast } from 'txforge'
33 | * import nimble from '@runonbitcoin/nimble'
34 | *
35 | * const { sha256, sha256d } = nimble.functions
36 | *
37 | * class HashPuzzle extends Cast {
38 | * lockingScript({ secret }) {
39 | * this.script
40 | * .push(opcodes.OP_SHA256)
41 | * .push(sha256d(secret))
42 | * .push(opcodes.OP_EQUAL)
43 | * }
44 | *
45 | * unlockingScript({ secret }) {
46 | * this.script.push(sha256(secret))
47 | * }
48 | * }
49 | * ```
50 | *
51 | * ## Using a Cast
52 | *
53 | * The following example shows the locking and subsequent unlocking of a coin
54 | * in two separate transactions.
55 | *
56 | * ```
57 | * import { forgeTx, getUtxo } from 'txforge'
58 | *
59 | * const secret = 'my super sEcReT password!!!1'
60 | *
61 | * const tx1 = forgeTx({
62 | * inputs: [...],
63 | * outputs: [
64 | * HashPuzzle.lock(1000, { secret })
65 | * ]
66 | * })
67 | *
68 | * const utxo = getUtxo(tx1, 0)
69 | *
70 | * const tx2 = forgeTx({
71 | * inputs: [
72 | * HashPuzzle.unlock(utxo, { secret })
73 | * ],
74 | * outputs: [...]
75 | * })
76 | * ```
77 | *
78 | * ## Testing Casts
79 | *
80 | * TxForge provides a built-in way of testing and simulating casts.
81 | *
82 | * ```
83 | * const secret = 'my super sEcReT password!!!1'
84 | *
85 | * // 1st arg is params given to `lockingScript`
86 | * // 2nd arg is params given to `unlockingScript`
87 | * HashPuzzle.simulate({ secret }, { secret })
88 | * ```
89 | */
90 | export class Cast {
91 | constructor(mode, { params, opts, satoshis, utxo }) {
92 | this.mode = mode
93 | this.params = params
94 | this.opts = opts
95 | this.satoshis = satoshis
96 | this.utxo = utxo
97 | this.script = new Tape(this)
98 | this.ctx = null
99 | this.init(params, opts)
100 | }
101 |
102 | /**
103 | * Locks the specified number of satoshis using the given parameters.
104 | *
105 | * @param {number} satoshis Number of satoshis to lock
106 | * @param {object} params Lock parameters
107 | * @param {object} opts Lock options
108 | * @returns {Cast}
109 | */
110 | static lock(satoshis, params, opts = {}) {
111 | return new this('lock', { satoshis, params, opts })
112 | }
113 |
114 | /**
115 | * Locks the specified utxo using the given parameters.
116 | *
117 | * @param {UTXO} utxo Locked UTXO
118 | * @param {object} params Unlock parameters
119 | * @param {object} opts Unlock options
120 | * @returns {Cast}
121 | */
122 | static unlock(utxo, params, opts = {}) {
123 | return new this('unlock', { utxo, params, opts })
124 | }
125 |
126 | /**
127 | * Simulates the Cast using the given lock and unlock parameters. Returns a
128 | * `vm` object from nimble's `evalScript` function.
129 | *
130 | * @param {object} params Lock parameters
131 | * @param {object} params Unlock parameters
132 | * @returns {object} evalScript vm object
133 | */
134 | static simulate(lockParams = {}, unlockParams = {}) {
135 | const lockTx = forgeTx({
136 | outputs: [this.lock(1000, lockParams)]
137 | })
138 |
139 | const utxo = getUTXO(lockTx, 0)
140 |
141 | const tx = forgeTx({
142 | inputs: [this.unlock(utxo, unlockParams)]
143 | })
144 |
145 | return evalScript(
146 | tx.inputs[0].script,
147 | lockTx.outputs[0].script,
148 | tx,
149 | 0,
150 | lockTx.outputs[0].satoshis,
151 | )
152 | }
153 |
154 | /**
155 | * Casts may implement the `init()` hook. This is useful for setting defaults
156 | * and coercing and/or validating the received parameters.
157 | *
158 | * @param {object} params Lock or unlock parameters
159 | * @param {object} opts Lock or unlock options
160 | * @returns {void}
161 | */
162 | init(params, opts) {}
163 |
164 | /**
165 | * The `lockingScript()` hook should be implemented to define the puzzle which
166 | * locks the coins.
167 | *
168 | * Refer to the {@link Tape} api.
169 | *
170 | * @param {object} params Lock or unlock parameters
171 | * @param {object} opts Lock or unlock options
172 | * @returns {void}
173 | */
174 | lockingScript(params, opts) {}
175 |
176 | /**
177 | * The `unlockingScript()` hook should be implemented to define the solution
178 | * to the puzzle under which coins are locked.
179 | *
180 | * Refer to the {@link Tape} api.
181 | *
182 | * @param {object} params Lock or unlock parameters
183 | * @param {object} opts Lock or unlock options
184 | * @returns {void}
185 | */
186 | unlockingScript(params, opts) {}
187 |
188 | /**
189 | * Compiles and returns the script.
190 | *
191 | * @returns {nimble.Script}
192 | */
193 | toScript() {
194 | this.script = new Tape(this)
195 | if (this.mode === 'lock') {
196 | this.lockingScript(this.params, this.opts)
197 | } else {
198 | this.unlockingScript(this.params, this.opts)
199 | }
200 |
201 | return toScript(this.script)
202 | }
203 |
204 | /**
205 | * Compiles the script and returns a transaction Input. Only available to
206 | * unlocking Casts.
207 | *
208 | * @returns {nimble.Transaction.Input}
209 | */
210 | toInput() {
211 | if (this.mode !== 'unlock') {
212 | throw new Error('invalid mode. `toInput()` only available in `unlock` mode.')
213 | }
214 |
215 | const { txid, vout, output } = this.utxo
216 | const script = this.toScript()
217 | const sequence = getOpt(this.opts, ['sequence'], 0xFFFFFFFF)
218 |
219 | return new Transaction.Input(txid, vout, script, sequence, output)
220 | }
221 |
222 | /**
223 | * Compiles the script and returns a transaction Output. Only available to
224 | * locking Casts.
225 | *
226 | * @returns {nimble.Transaction.Output}
227 | */
228 | toOutput() {
229 | if (this.mode !== 'lock') {
230 | throw new Error('invalid mode. `toOutput()` only available in `lock` mode.')
231 | }
232 |
233 | const script = this.toScript()
234 | return new Transaction.Output(script, this.satoshis)
235 | }
236 |
237 | /**
238 | * Sets the transaction context on the cast.
239 | *
240 | * @param {nimble.Transaction} tx Current transaction
241 | * @param {number} vin Input index
242 | * @returns {void}
243 | */
244 | setCtx(tx, vin) {
245 | this.ctx = { tx, vin }
246 | }
247 | }
248 |
249 | /**
250 | * Checks if the given class extends from Cast.
251 | *
252 | * @param {class} cast Cast class
253 | * @returns {boolean}
254 | */
255 | export function isCast(cast) {
256 | return cast &&
257 | Object.getPrototypeOf(cast.constructor).name === 'Cast' &&
258 | (typeof cast.lockingScript === 'function' || typeof cast.unlockingScript === 'function')
259 | }
260 |
--------------------------------------------------------------------------------
/src/classes/forge.js:
--------------------------------------------------------------------------------
1 | import nimble from '@runonbitcoin/nimble'
2 | import { isCast } from './cast.js'
3 | import { P2PKH, Raw } from '../casts/index.js'
4 |
5 | const { BufferWriter, Transaction } = nimble.classes
6 | const { writeVarint } = nimble.functions
7 |
8 | const defaults = {
9 | rates: { data: 50, standard: 50 },
10 | sort: false,
11 | }
12 |
13 | /**
14 | * Forge is an industrial strength transaction builder.
15 | *
16 | * Use Casts to forge transactions of any shape and size, using any script
17 | * template imaginable.
18 | *
19 | * @see createForge
20 | * @see forgeTx
21 | */
22 | export class Forge {
23 | constructor({ inputs, outputs, change, locktime, options } = {}) {
24 | this.inputs = []
25 | this.outputs = []
26 | this.changeScript = null
27 | this.locktime = 0
28 | this.options = {
29 | ...defaults,
30 | ...options
31 | }
32 |
33 | if (inputs) this.addInput(inputs)
34 | if (outputs) this.addOutput(outputs)
35 |
36 | if (Array.isArray(change)) {
37 | this.changeTo(...change)
38 | } else if (typeof change === 'object') {
39 | this.changeTo(change)
40 | }
41 |
42 | if (Number.isInteger(locktime)) {
43 | this.locktime = locktime
44 | }
45 | }
46 |
47 | get inputSum() {
48 | return this.inputs.reduce((sum, i) => sum + i.utxo.satoshis || 0, 0)
49 | }
50 |
51 | get outputSum() {
52 | return this.outputs.reduce((sum, o) => sum + o.satoshis, 0)
53 | }
54 |
55 | /**
56 | * Adds the given unlocking Cast (or array of Casts) to the forge.
57 | *
58 | * @param {Cast|Cast[]} cast Unlocking cast(s)
59 | * @returns {Forge}
60 | */
61 | addInput(cast) {
62 | if (Array.isArray(cast)) {
63 | cast.forEach(c => this.addInput(c))
64 | return this
65 | }
66 |
67 | if (isCast(cast) && cast.mode === 'unlock') {
68 | this.inputs.push(cast)
69 | } else {
70 | throw new Error('invalid input not added')
71 | }
72 |
73 | return this
74 | }
75 |
76 | /**
77 | * Adds the given locking Cast (or array of Casts) to the forge.
78 | *
79 | * @param {Cast|Cast[]} cast Locking cast(s)
80 | * @returns {Forge}
81 | */
82 | addOutput(cast) {
83 | if (Array.isArray(cast)) {
84 | cast.forEach(c => this.addOutput(c))
85 | return this
86 | }
87 |
88 | if (isCast(cast) && cast.mode === 'lock') {
89 | this.outputs.push(cast)
90 | } else {
91 | throw new Error('invalid output not added')
92 | }
93 |
94 | return this
95 | }
96 |
97 | /**
98 | * Sets the forge changeScript based on the given Cast class and params.
99 | * The first argument can be omitted if the params contains an `address` or
100 | * `script` property - in such cases the `P2PKH` or `Raw` Casts are used to
101 | * create the changeScript.
102 | *
103 | * ## Examples
104 | *
105 | * ```
106 | * // Sets a P2PK change script
107 | * forge.changeTo(P2PK, { pubkey })
108 | *
109 | * // Will automatically use P2PKH
110 | * forge.changeTo({ address })
111 | *
112 | * // Will automatically use Raw
113 | * forge.changeTo({ script })
114 | * ```
115 | *
116 | * @param {class|object} classOrParams Cast class or lock parameters
117 | * @param {object?} params Lock parameters
118 | * @returns
119 | */
120 | changeTo(classOrParams, params) {
121 | if (Object.getPrototypeOf(classOrParams).name === 'Cast') {
122 | this.changeScript = classOrParams.lock(0, params || {}).toScript()
123 | } else if (!!classOrParams.address) {
124 | this.changeScript = P2PKH.lock(0, classOrParams).toScript()
125 | } else if (!!classOrParams.script) {
126 | this.changeScript = Raw.lock(0, classOrParams).toScript()
127 | } else {
128 | throw new Error('invalid change params. must give cast class and lock params')
129 | }
130 |
131 | return this
132 | }
133 |
134 | /**
135 | * Calculates the fee required for miners to accept the transaction (according
136 | * to the configured rates).
137 | *
138 | * @param {object?} rates Miner rates
139 | */
140 | calcRequiredFee(rates = this.options.rates) {
141 | const inScripts = this.inputs.map(i => i.toScript())
142 | const outScripts = this.outputs.map(o => o.toScript())
143 |
144 | // Initially consider all bytes standard
145 | const bytes = {
146 | standard: [
147 | 8,
148 | varintSize(inScripts.length),
149 | varintSize(outScripts.length),
150 | inScripts.reduce((sum, script) => sum + inputSize(script), 0),
151 | outScripts.reduce((sum, script) => sum + outputSize(script), 0)
152 | ].reduce((sum, i) => sum + i, 0),
153 | data: 0
154 | }
155 |
156 | // Detect data outputs and adjust bytes
157 | outScripts
158 | .filter(s => /^006a/.test(s.toHex()))
159 | .forEach(s => {
160 | const len = outputSize(s)
161 | bytes.standard -= len
162 | bytes.data += len
163 | })
164 |
165 | // Calculate the fee for both standard and date bytes
166 | const fee = ['standard', 'data'].reduce((sum, type) => {
167 | const rate = Number.isInteger(rates) ? rates : rates[type]
168 | return sum + (bytes[type] * rate / 1000)
169 | }, 0)
170 |
171 | return Math.ceil(fee)
172 | }
173 |
174 | /**
175 | * Sorts the inputs and outputs according to
176 | * {@link https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki BIP-69}.
177 | *
178 | * BIP-69 defines deterministic lexographical indexing of transaction inputs
179 | * and outputs.
180 | *
181 | * @returns {Forge}
182 | */
183 | sort() {
184 | this.inputs.sort((a, b) => {
185 | return a.utxo.txid.localeCompare(b.utxo.txid) || (a.utxo.vout - b.utxo.vout)
186 | })
187 |
188 | this.outputs.sort((a, b) => {
189 | return (a.satoshis - b.satoshis) || a.toScript().toHex().localeCompare(b.toScript().toHex())
190 | })
191 |
192 | return this
193 | }
194 |
195 | /**
196 | * Builds and returns a signed transaction.
197 | *
198 | * @returns {nimble.Transaction}
199 | */
200 | toTx() {
201 | if (this.options.sort) {
202 | this.sort()
203 | }
204 |
205 | const tx = new Transaction()
206 |
207 | // First pass populate inputs with zero'd sigs
208 | this.inputs.forEach(cast => tx.input(cast.toInput()))
209 | this.outputs.forEach(cast => tx.output(cast.toOutput()))
210 |
211 | // If changeScript exists, calculate the change and add to tx
212 | if (this.changeScript) {
213 | const rates = this.options.rates
214 | const rate = Number.isInteger(rates) ? rates : rates.standard
215 | const fee = this.calcRequiredFee()
216 | const extraFee = Math.ceil(outputSize(this.changeScript) * rate / 1000)
217 | const change = (this.inputSum - this.outputSum) - (fee + extraFee)
218 | if (change > 0) {
219 | tx.output(new Transaction.Output(this.changeScript, change, tx))
220 | }
221 | }
222 |
223 | if (this.locktime > 0) {
224 | tx.locktime = this.locktime
225 | }
226 |
227 | // Second pass replaces signed inputs
228 | this.inputs.forEach((cast, vin) => {
229 | cast.setCtx(tx, vin)
230 | tx.inputs[vin].script = cast.toScript()
231 | })
232 |
233 | return tx
234 | }
235 | }
236 |
237 | /**
238 | * Creates and returns a forge instance from the given params.
239 | *
240 | * ## Examples
241 | *
242 | * ```
243 | * createForge({
244 | * inputs: [
245 | * P2PKH.unlock(utxo, { privkey })
246 | * ],
247 | * outputs: [
248 | * P2PKH.lock(10000, { address })
249 | * ],
250 | * change: { address: changeAddress }
251 | * })
252 | * ```
253 | *
254 | * @param {cast[]} params.inputs Array of unlocking casts
255 | * @param {cast[]} params.outputs Array of locking casts
256 | * @param {[class, object]|object?} params.change Change Cast class and lock parameters
257 | * @param {number?} params.locktime Transaction locktime integer
258 | * @param {object?} params.options.rates Miner fee quote
259 | * @param {boolean?} params.options.sort Automatically sort using BIP-69
260 | * @returns {Cast}
261 | */
262 | export function createForge(params = {}) {
263 | return new Forge(params)
264 | }
265 |
266 | /**
267 | * As {@link createForge} but returns built and signed transaction.
268 | *
269 | * ```
270 | * forgeTx({
271 | * inputs: [
272 | * P2PKH.unlock(utxo, { privkey })
273 | * ],
274 | * outputs: [
275 | * P2PKH.lock(10000, { address })
276 | * ],
277 | * change: { address: changeAddress }
278 | * })
279 | * ```
280 | *
281 | * @param {cast[]} params.inputs Array of unlocking casts
282 | * @param {cast[]} params.outputs Array of locking casts
283 | * @param {[class, object]|object?} params.change Change Cast class and lock parameters
284 | * @param {number?} params.locktime Transaction locktime integer
285 | * @param {object?} params.options.rates Miner fee quote
286 | * @param {boolean?} params.options.sort Automatically sort using BIP-69
287 | * @returns {nimble.Transaction}
288 | */
289 | export function forgeTx(params = {}) {
290 | const forge = new Forge(params)
291 | return forge.toTx()
292 | }
293 |
294 | // Returns the byte size of a TxIn with the given script.
295 | function inputSize(script) {
296 | const buf = new BufferWriter()
297 | writeVarint(buf, script.length)
298 | buf.write(script.buffer)
299 | return 36 + buf.length + 4
300 | }
301 |
302 | // Returns the byte size of a TxOut with the given script.
303 | function outputSize(script) {
304 | const buf = new BufferWriter()
305 | writeVarint(buf, script.length)
306 | buf.write(script.buffer)
307 | return 8 + buf.length
308 | }
309 |
310 | // Returns the byte size of a VarInt of the given integer.
311 | function varintSize(num) {
312 | const buf = new BufferWriter()
313 | writeVarint(buf, num)
314 | return buf.length
315 | }
316 |
--------------------------------------------------------------------------------
/src/classes/shared.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Searches the given parameters and returns the first value found from the
3 | * array of keys. Optionally a default value can be set in case none of the keys
4 | * exist.
5 | *
6 | * @param {object} params Parameters object
7 | * @param {string[]} keys List of keys
8 | * @param {any} defaultVal Default value
9 | */
10 | export function getOpt(params = {}, keys = [], defaultVal) {
11 | for (let i = 0; i < keys.length; i++) {
12 | const key = keys[i], val = params[key]
13 | if (typeof val !== 'undefined') return val;
14 | }
15 |
16 | return defaultVal
17 | }
--------------------------------------------------------------------------------
/src/classes/tape.js:
--------------------------------------------------------------------------------
1 | import nimble from '@runonbitcoin/nimble'
2 |
3 | const { BufferWriter, Script } = nimble.classes
4 | const { opcodes } = nimble.constants
5 | const { isBuffer } = nimble.functions
6 |
7 | /**
8 | * The Tape class is a Bitcoin Script builder. Each Cast instance has a Tape
9 | * instance on the `script` property.
10 | *
11 | * Tape provides a simple API for pushing new cells containing Op Codes or data
12 | * vectors onto the tape. Tape functions can be chained together.
13 | *
14 | * The tape is later compiled to a Script instance.
15 | */
16 | export class Tape {
17 | constructor(cast) {
18 | this.cast = cast ? cast : { script: this }
19 | this.cells = []
20 | }
21 |
22 | /**
23 | * Applies the macro function with the given array of arguments. The function
24 | * will be invoked with the Cast instance as the `this` context.
25 | *
26 | * ## Example
27 | *
28 | * ```
29 | * // Define a macro
30 | * function hello(data) {
31 | * this.script.push('hello').push(data)
32 | * }
33 | *
34 | * // Apply the macro
35 | * tape.apply(hello, ['world'])
36 | * ```
37 | *
38 | * @param {function} macro Macro function
39 | * @param {any[]} args Array of arguments
40 | * @return {Tape}
41 | */
42 | apply(macro, args = []) {
43 | if (typeof macro !== 'function') {
44 | throw new Error(`invalid argument. callback must be a function.`)
45 | }
46 | if (!Array.isArray(args)) {
47 | throw new Error(`invalid args. must be an array of arguments.`)
48 | }
49 |
50 | macro.apply(this.cast, args)
51 | return this
52 | }
53 |
54 | /**
55 | * Pushes the given data onto the Tape. `data` can be an Op Code, string or
56 | * byte vector, or an array of these types.
57 | *
58 | * To push integers onto the stack, first convert to a Script Num using the
59 | * {@link num `num()` helper}.
60 | *
61 | * @param {any | any[]} data Push data
62 | * @return {Tape}
63 | */
64 | push(data) {
65 | if (typeof data === 'object' && (Number.isInteger(data.opcode) || isBuffer(data.buf))) {
66 | this.cells.push(data)
67 | return this
68 | }
69 |
70 | if (isBuffer(data)) return this.push({ buf: data });
71 |
72 | if (Array.isArray(data)) {
73 | data.forEach(part => this.push(part))
74 | return this
75 | }
76 |
77 | if (data && typeof data.toBuffer === 'function') {
78 | return this.push(data.toBuffer())
79 | }
80 |
81 | switch(typeof data) {
82 | case 'number': return this.push(opcode(data));
83 | case 'string': return this.push(string(data));
84 | }
85 |
86 | throw new Error(`invalid push value. type ${typeof data} not supported.`)
87 | }
88 |
89 | /**
90 | * Iterates over the given elements invoking the callback on each. The
91 | * callback will be invoked with the Cast instance as the `this` context.
92 | *
93 | * ## Example
94 | *
95 | * ```
96 | * tape.each(['foo', 'bar'], (el, i) => {
97 | * tape.push(el)
98 | * })
99 | * ```
100 | *
101 | * @param {any[]} elements Iterable elements
102 | * @param {function} callback Callback function
103 | * @return {Tape}
104 | */
105 | each(elements, callback) {
106 | if (!Array.isArray(elements)) {
107 | throw new Error(`invalid each. first argument must be an array.`)
108 | }
109 |
110 | for (let i = 0; i < elements.length; i++) this.apply(callback, [elements[i], i])
111 | return this
112 | }
113 |
114 | /**
115 | * Iterates the given number of times invoking the callback on each loop. The
116 | * callback will be invoked with the Cast instance as the `this` context.
117 | *
118 | * ## Example
119 | *
120 | * ```
121 | * tape.repeat(15, (i) => {
122 | * tape.push(OP_1)
123 | * tape.push(OP_SPLIT)
124 | * })
125 | * ```
126 | *
127 | * @param {any[]} elements Iterable elements
128 | * @param {function} callback Callback function
129 | * @return {Tape}
130 | */
131 | repeat(n, callback) {
132 | if (!Number.isInteger(n) || n < 1) {
133 | throw new Error(`invalid repeat. first argument must be non-negative integer.`)
134 | }
135 |
136 | for (let i = 0; i < n; i++) this.apply(callback, [i])
137 | return this
138 | }
139 | }
140 |
141 | /**
142 | * Compiles the given tape and returns a Bitcoin Script instance.
143 | *
144 | * @param {Tape} tape Tape instance
145 | * @returns {nimble.Script}
146 | */
147 | export function toScript(tape) {
148 | if (!(tape && Array.isArray(tape.cells))) {
149 | throw new Error('invalid argument. `toScript()` must be given a Tape instance.')
150 | }
151 |
152 | const buf = new BufferWriter()
153 |
154 | for (let i = 0; i < tape.cells.length; i++) {
155 | const cell = tape.cells[i]
156 |
157 | if (cell.buf && cell.buf.length) {
158 | if (cell.buf.length < 76) {
159 | buf.write([cell.buf.length])
160 | buf.write(cell.buf)
161 | } else if (cell.buf.length < 0x100) {
162 | buf.write([76])
163 | buf.write(uint8(cell.buf.length))
164 | buf.write(cell.buf)
165 | } else if (cell.buf.length < 0x10000) {
166 | buf.write([77])
167 | buf.write(uint16(cell.buf.length))
168 | buf.write(cell.buf)
169 | } else if (cell.buf.length < 0x100000000) {
170 | buf.write([78])
171 | buf.write(uint32(cell.buf.length))
172 | buf.write(cell.buf)
173 | } else {
174 | throw new Error('pushdata cannot exceed 4,294,967,296 bytes')
175 | }
176 | } else if (Number.isInteger(cell.opcode)) {
177 | buf.write([cell.opcode])
178 | }
179 | }
180 |
181 | return new Script(buf.toBuffer())
182 | }
183 |
184 | // Casts byte as an opcode object
185 | function opcode(byte) {
186 | if (!Number.isInteger(byte) || !Object.values(opcodes).includes(byte)) {
187 | throw new Error('Invalid push value. Must be valid OP CODE byte value.')
188 | }
189 |
190 | return { opcode: byte }
191 | }
192 |
193 | // Casts string as a utf8 buffer
194 | function string(str) {
195 | const enc = new TextEncoder()
196 | return enc.encode(str)
197 | }
198 |
199 | // Casts integer as a Uint8Array
200 | function uint8(num) {
201 | const buf = new ArrayBuffer(1)
202 | const view = new DataView(buf)
203 | view.setUint8(0, num)
204 | return new Uint8Array(view.buffer)
205 | }
206 |
207 | // Casts integer as a Uint16Array
208 | function uint16(num) {
209 | const buf = new ArrayBuffer(2)
210 | const view = new DataView(buf)
211 | view.setUint16(0, num, true)
212 | return new Uint8Array(view.buffer)
213 | }
214 |
215 | // Casts integer as a Uint32Array
216 | function uint32(num) {
217 | const buf = new ArrayBuffer(4)
218 | const view = new DataView(buf)
219 | view.setUint32(0, num, true)
220 | return new Uint8Array(view.buffer)
221 | }
222 |
--------------------------------------------------------------------------------
/src/classes/utxo.js:
--------------------------------------------------------------------------------
1 | import nimble from '@runonbitcoin/nimble'
2 | import { getOpt } from './shared.js'
3 |
4 | const { Script, Transaction } = nimble.classes
5 | const { isHex } = nimble.functions
6 |
7 | /**
8 | * A UTXO is an Unspent Transaction Output.
9 | *
10 | * Unlocking Casts spend UTXOs so it is usually required to prepare UTXO
11 | * instances using data from your UTXO database or api.
12 | *
13 | * See {@link toUTXO}.
14 | */
15 | export class UTXO {
16 | constructor({ txid, vout, satoshis, script } = {}) {
17 | this.txid = txid
18 | this.vout = vout
19 | this.satoshis = satoshis
20 | this.script = script
21 | }
22 |
23 | get output() {
24 | if (this.satoshis && this.script) {
25 | return new Transaction.Output(this.script, this.satoshis)
26 | }
27 | }
28 | }
29 |
30 | /**
31 | * Creates a UTXO from the given parameters.
32 | *
33 | * Will intelligently handle parameters from most UTXO apis.
34 | *
35 | * @param {string|nimble.Script} params.script Previous output script
36 | * @param {string?} params.txid Transaction ID
37 | * @param {string?} params.tx_hash Transaction ID
38 | * @param {number?} params.satoshis Previous output satoshis
39 | * @param {number?} params.value Previous output satoshis
40 | * @param {number?} params.vout Previous output index
41 | * @param {number?} params.outputIndex Previous output index
42 | * @param {number?} params.tx_pos Previous output index
43 | * @returns {UTXO}
44 | */
45 | export function toUTXO({ script, ...params } = {}) {
46 | const txid = getOpt(params, ['txid', 'tx_hash'])
47 | const vout = getOpt(params, ['vout', 'outputIndex', 'tx_pos'])
48 | const satoshis = getOpt(params, ['satoshis', 'value'])
49 |
50 | if (isHex(script)) {
51 | script = Script.fromHex(script)
52 | }
53 |
54 | return new UTXO({ txid, vout, satoshis, script })
55 | }
56 |
57 | /**
58 | * Get a UTXO from the given transaction and output index.
59 | *
60 | * @param {nimble.Transaction} tx Transaction
61 | * @param {number} vout Transaction output index
62 | */
63 | export function getUTXO(tx, vout) {
64 | if (!tx || !tx.outputs[vout]) {
65 | throw new Error(`cannot create utxo from given tx and vout (${ vout })`)
66 | }
67 |
68 | return new UTXO({
69 | txid: tx.hash,
70 | vout,
71 | satoshis: tx.outputs[vout].satoshis,
72 | script: tx.outputs[vout].script,
73 | })
74 | }
75 |
--------------------------------------------------------------------------------
/src/extra/r-puzzle.js:
--------------------------------------------------------------------------------
1 | import nimble from '@runonbitcoin/nimble'
2 | import { BN_SIZE, PT_SIZE, getMemoryBuffer, getSecp256k1Exports, writeBN, readBN } from '@runonbitcoin/nimble/wasm/wasm-secp256k1.js'
3 |
4 | const { encodeHex, generatePrivateKey } = nimble.functions
5 |
6 | const secp256k1_N = BigInt('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141')
7 |
8 | /**
9 | * Generates and returns a random K value.
10 | *
11 | * @returns {Uint8Array}
12 | */
13 | export const generateK = generatePrivateKey
14 |
15 | /**
16 | * Calculates and returns the R value from the give K value.
17 | *
18 | * @param {Uint8Array} k K value
19 | * @returns {Uint8Array}
20 | */
21 | export function calculateR(k) {
22 | const memory = getMemoryBuffer()
23 | const privateKeyPos = memory.length - BN_SIZE
24 | const publicKeyPos = privateKeyPos - PT_SIZE
25 |
26 | writeBN(memory, privateKeyPos, k)
27 |
28 | getSecp256k1Exports().g_mul(publicKeyPos, privateKeyPos)
29 |
30 | const point = {
31 | x: readBN(memory, publicKeyPos),
32 | y: readBN(memory, publicKeyPos + BN_SIZE)
33 | }
34 |
35 | const rBn = BigInt(`0x${ encodeHex(point.x) }`) % secp256k1_N
36 | const rBuf = bnToBuf(rBn)
37 |
38 | if (rBuf[0] > 127) {
39 | const buf = new Uint8Array(rBuf.length + 1)
40 | buf.set([0], 0)
41 | buf.set(rBuf, 1)
42 | return buf
43 | } else {
44 | return rBuf
45 | }
46 | }
47 |
48 | // Converts js bigint to uint8array
49 | function bnToBuf(bn) {
50 | var hex = BigInt(bn).toString(16);
51 | if (hex.length % 2) { hex = '0' + hex; }
52 |
53 | var len = hex.length / 2;
54 | var u8 = new Uint8Array(len);
55 |
56 | var i = 0;
57 | var j = 0;
58 | while (i < len) {
59 | u8[i] = parseInt(hex.slice(j, j+2), 16);
60 | i += 1;
61 | j += 2;
62 | }
63 |
64 | return u8;
65 | }
66 |
--------------------------------------------------------------------------------
/src/helpers/asm.js:
--------------------------------------------------------------------------------
1 | import nimble from '@runonbitcoin/nimble'
2 |
3 | const { decodeASM, decodeScriptChunks } = nimble.functions
4 |
5 | /**
6 | * Decodes the ASM string and returns array of script chunks.
7 | *
8 | * @param {string} str ASM string
9 | * @returns {array}
10 | */
11 | export function asm(str) {
12 | return decodeScriptChunks(decodeASM(str))
13 | }
14 |
--------------------------------------------------------------------------------
/src/helpers/index.js:
--------------------------------------------------------------------------------
1 | export { asm } from './asm.js'
2 | export { num, scriptNum } from './num.js'
--------------------------------------------------------------------------------
/src/helpers/num.js:
--------------------------------------------------------------------------------
1 | import nimble from '@runonbitcoin/nimble'
2 |
3 | const { decodeHex } = nimble.functions
4 |
5 | /**
6 | * If num is 0-16 the appropriate opcode is returned. otherwise a ScriptNum
7 | * buffer is returned.
8 | *
9 | * @param {number} num Number
10 | * @returns {number|number[]}
11 | */
12 | export function num(num) {
13 | if (num === 0) {
14 | return 0;
15 | } else if (num > 0 && num <= 16) {
16 | return num + 80
17 | } else {
18 | return scriptNum(num)
19 | }
20 | }
21 |
22 | /**
23 | * Encodes the given integer as a ScriptNum byte vector.
24 | *
25 | * @param {number} num Number
26 | * @returns {number[]}
27 | */
28 | export function scriptNum(num) {
29 | if (num === 0) return []
30 | const neg = num < 0
31 | const arr = Array.from(decodeHex(BigInt(num).toString(16))).reverse()
32 | const full = arr[arr.length - 1] & 0x80
33 | if (full) arr.push(0x00)
34 | if (neg) arr[arr.length - 1] |= 0x80
35 | return arr
36 | }
37 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import nimble from '@runonbitcoin/nimble'
2 |
3 | export { Forge, createForge, forgeTx } from './classes/forge.js'
4 | export { Cast, isCast } from './classes/cast.js'
5 | export { Tape, toScript } from './classes/tape.js'
6 | export { UTXO, toUTXO, getUTXO } from './classes/utxo.js'
7 | export * as casts from './casts/index.js'
8 | export * as helpers from './helpers/index.js'
9 | export * as macros from './macros/index.js'
10 |
11 | export const deps = {
12 | nimble
13 | }
14 |
--------------------------------------------------------------------------------
/src/macros/binary.js:
--------------------------------------------------------------------------------
1 | import nimble from '@runonbitcoin/nimble'
2 | import { num } from '../helpers/index.js'
3 |
4 | const { OP_1, OP_BIN2NUM, OP_CAT, OP_DROP, OP_NIP, OP_SIZE, OP_SPLIT, OP_SUB, OP_SWAP } = nimble.constants.opcodes
5 |
6 | /**
7 | * Decodes the top stack element as a ScriptNum encoded number.
8 | *
9 | * @param {string} endian Endianness (defaults 'le')
10 | * @returns {void}
11 | */
12 | export function decodeUint(endian = 'le') {
13 | if (['be', 'big'].includes(endian)) {
14 | throw new Error('big endian decoding not implemented yet')
15 |
16 | } else {
17 | this.script
18 | .push([0])
19 | .push(OP_CAT)
20 | .push(OP_BIN2NUM)
21 | }
22 | }
23 |
24 | /**
25 | * Reverses the top item on the stack.
26 | *
27 | * This macro pushes op codes on to the script that will reverse a binary of the
28 | * given length.
29 | *
30 | * @param {number} len Length in bytes
31 | * @returns {void}
32 | */
33 | export function reverse(len) {
34 | for (let i = 1; i < len; i++) {
35 | this.script.push(OP_1).push(OP_SPLIT)
36 | }
37 |
38 | for (let i = 1; i < len; i++) {
39 | this.script.push(OP_SWAP).push(OP_CAT)
40 | }
41 | }
42 |
43 | /**
44 | * Slices bytes from top item on the stack, starting on the given `start` index
45 | * for `length` bytes. The stack item is replaced with the sliced value.
46 | *
47 | * Byte vectors are zero indexed. If `start` is a negative integer, then the
48 | * start index is counted from the end.
49 | *
50 | * @param {number} start Start index
51 | * @param {number} length Bytes to slice
52 | * @returns {void}
53 | */
54 | export function slice(start, length) {
55 | if (start === 0) {
56 | this.script
57 | .push(num(length))
58 | .push(OP_SPLIT)
59 | .push(OP_DROP)
60 |
61 | } else if (start > 0) {
62 | this.script
63 | .apply(trim, [start])
64 | .apply(slice, [0, length])
65 |
66 | } else if (start < 0) {
67 | this.script
68 | .push(OP_SIZE)
69 | .push(num(start * -1))
70 | .push(OP_SUB)
71 | .push(OP_SPLIT)
72 | .push(OP_NIP)
73 | .apply(slice, [0, length])
74 | }
75 | }
76 |
77 | /**
78 | * Trims the given number of leading or trailing bytes from the top item on the
79 | * stack. The stack item is replaced with the trimmed value.
80 | *
81 | * When the given `length` is a positive integer, leading bytes are trimmed.
82 | * When a negative integer is given, trailing bytes are trimmed.
83 | *
84 | * @param {number} length Bytes to trim
85 | * @returns {void}
86 | */
87 | export function trim(length) {
88 | if (length > 0) {
89 | this.script
90 | .push(num(length))
91 | .push(OP_SPLIT)
92 | .push(OP_NIP)
93 |
94 | } else if (length < 0) {
95 | this.script
96 | .push(OP_SIZE)
97 | .push(num(length * -1))
98 | .push(OP_SUB)
99 | .push(OP_SPLIT)
100 | .push(OP_DROP)
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/macros/index.js:
--------------------------------------------------------------------------------
1 | export { decodeUint, reverse, slice, trim } from './binary.js'
2 | export {
3 | getVersion, getPrevoutsHash, getSequenceHash, getOutpoint,
4 | getScript, getSatoshis, getSequence, getOutputsHash,
5 | getLocktime, getSighashType,
6 | pushTx, checkTx, checkTxVerify, checkTxOpt, checkTxOptVerify
7 | } from './push-tx.js'
8 | export { signTx, signTxWithK } from './sign-tx.js'
9 | export { getVarint, readVarint, trimVarint } from './varint.js'
10 |
--------------------------------------------------------------------------------
/src/macros/push-tx.js:
--------------------------------------------------------------------------------
1 | import nimble from '@runonbitcoin/nimble'
2 | import { asm } from '../helpers/index.js'
3 | import { decodeUint, reverse, slice, trim } from './binary.js'
4 | import { trimVarint } from './varint.js'
5 |
6 | const {
7 | OP_CAT, OP_DUP, OP_HASH256, OP_SPLIT, OP_SWAP, OP_TUCK,
8 | OP_IF, OP_ELSE, OP_ENDIF, OP_CHECKSIG, OP_CHECKSIGVERIFY
9 | } = nimble.constants.opcodes
10 | const { decodeHex, preimage } = nimble.functions
11 |
12 | const ORDER_PREFIX = decodeHex('414136d08c5ed2bf3ba048afe6dcaebafe')
13 | const PUBKEY_A = decodeHex('023635954789a02e39fb7e54440b6f528d53efd65635ddad7f3c4085f97fdbdc48')
14 | const PUBKEY_B = decodeHex('038ff83d8cf12121491609c4939dc11c4aa35503508fe432dc5a5c1905608b9218')
15 | const PUBKEY_OPT = decodeHex('02b405d7f0322a89d0f9f3a98e6f938fdc1c969a8d1382a2bf66a71ae74a1e83b0')
16 | const SIG_PREFIX = decodeHex('3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817980220')
17 | const SIGHASH_FLAG = 0x41
18 |
19 | /**
20 | * Assuming the top stack item is a Tx Preimage, gets the tx version number and
21 | * places it on the stack on top of the preimage.
22 | *
23 | * @returns {void}
24 | */
25 | export function getVersion() {
26 | this.script
27 | .push(OP_DUP)
28 | .apply(slice, [0, 4])
29 | .apply(decodeUint)
30 | }
31 |
32 | /**
33 | * Assuming the top stack item is a Tx Preimage, gets the 32 byte prevouts hash
34 | * and places it on the stack on top of the preimage.
35 | *
36 | * @returns {void}
37 | */
38 | export function getPrevoutsHash() {
39 | this.script
40 | .push(OP_DUP)
41 | .apply(slice, [4, 32])
42 | }
43 |
44 | /**
45 | * Assuming the top stack item is a Tx Preimage, gets the 32 byte sequence hash
46 | * and places it on the stack on top of the preimage.
47 | *
48 | * @returns {void}
49 | */
50 | export function getSequenceHash() {
51 | this.script
52 | .push(OP_DUP)
53 | .apply(slice, [36, 32])
54 | }
55 |
56 | /**
57 | * Assuming the top stack item is a Tx Preimage, gets the 36 byte outpoint and
58 | * places it on the stack on top of the preimage.
59 | *
60 | * @returns {void}
61 | */
62 | export function getOutpoint() {
63 | this.script
64 | .push(OP_DUP)
65 | .apply(slice, [68, 36])
66 | }
67 |
68 | /**
69 | * Assuming the top stack item is a Tx Preimage, gets the locking script and
70 | * places it on the stack on top of the preimage.
71 | *
72 | * State can be placed in the locking script and so this becomes an invaluable
73 | * method for extracting and using that state.
74 | *
75 | * @returns {void}
76 | */
77 | export function getScript() {
78 | this.script
79 | .push(OP_DUP)
80 | .apply(trim, [104])
81 | .apply(trim, [-52])
82 | .apply(trimVarint)
83 | }
84 |
85 | /**
86 | * Assuming the top stack item is a Tx Preimage, gets the input satoshis number
87 | * and places it on the stack on top of the preimage.
88 | *
89 | * @returns {void}
90 | */
91 | export function getSatoshis() {
92 | this.script
93 | .push(OP_DUP)
94 | .apply(slice, [-52, 8])
95 | .apply(decodeUint)
96 | }
97 |
98 | /**
99 | * Assuming the top stack item is a Tx Preimage, gets the input sequence number
100 | * and places it on the stack on top of the preimage.
101 | *
102 | * @returns {void}
103 | */
104 | export function getSequence() {
105 | this.script
106 | .push(OP_DUP)
107 | .apply(slice, [-44, 4])
108 | .apply(decodeUint)
109 | }
110 |
111 | /**
112 | * Assuming the top stack item is a Tx Preimage, gets the 32 byte outputs hash
113 | * and places it on the stack on top of the preimage.
114 | *
115 | * @returns {void}
116 | */
117 | export function getOutputsHash() {
118 | this.script
119 | .push(OP_DUP)
120 | .apply(slice, [-40, 32])
121 | }
122 |
123 | /**
124 | * Assuming the top stack item is a Tx Preimage, gets the tx locktime number and
125 | * places it on the stack on top of the preimage.
126 | *
127 | * @returns {void}
128 | */
129 | export function getLocktime() {
130 | this.script
131 | .push(OP_DUP)
132 | .apply(slice, [-8, 4])
133 | .apply(decodeUint)
134 | }
135 |
136 | /**
137 | * Assuming the top stack item is a Tx Preimage, gets the preimage sighash type
138 | * and places it on the stack on top of the preimage.
139 | *
140 | * @returns {void}
141 | */
142 | export function getSighashType() {
143 | this.script
144 | .push(OP_DUP)
145 | .apply(slice, [-4, 4])
146 | .apply(decodeUint)
147 | }
148 |
149 | /**
150 | * Pushes the current Tx Preimage onto the stack. If no tx context is available,
151 | * then 181 bytes of zeros are pushed onto the script instead.
152 | *
153 | * @returns {void}
154 | */
155 | export function pushTx() {
156 | const preimg = this.ctx ?
157 | preimage(
158 | this.ctx.tx,
159 | this.ctx.vin,
160 | this.utxo.script,
161 | this.utxo.satoshis,
162 | SIGHASH_FLAG
163 | ) :
164 | new Uint8Array(181);
165 |
166 | this.script.push(preimg)
167 | }
168 |
169 | /**
170 | * Assuming the top stack item is a Tx Preimage, creates and verifies a
171 | * signature with `OP_CHECKSIG`.
172 | *
173 | * The Tx Preimage is removed from the stack and replaced with the result from
174 | * `OP_CHECKSIG`.
175 | *
176 | * @returns {void}
177 | */
178 | export function checkTx() {
179 | this.script
180 | .push(OP_HASH256)
181 | .apply(prepareSighash)
182 | .apply(pushOrder)
183 | .apply(divOrder)
184 | .apply(sighashMSBis0or255)
185 | .push(asm('OP_IF OP_2 OP_PICK OP_ADD OP_ELSE OP_1ADD OP_ENDIF'))
186 | .apply(sighashModGtOrder)
187 | .push(asm('OP_IF OP_SUB OP_ELSE OP_NIP OP_ENDIF'))
188 | .apply(pushSig)
189 | .push(OP_SWAP)
190 | .push(OP_IF)
191 | .push(PUBKEY_A)
192 | .push(OP_ELSE)
193 | .push(PUBKEY_B)
194 | .push(OP_ENDIF)
195 | .push(OP_CHECKSIG)
196 | }
197 |
198 | /**
199 | * As {@link checkTx} but verifies the signature with `OP_CHECKSIGVERIFY`.
200 | *
201 | * @returns {void}
202 | */
203 | export function checkTxVerify() {
204 | this.script.apply(checkTx)
205 | this.script.cells.pop()
206 | this.script.push(OP_CHECKSIGVERIFY)
207 | }
208 |
209 | // Prepares the sighash and MSB
210 | function prepareSighash() {
211 | this.script
212 | .apply(reverse, [32])
213 | .push([0x1F])
214 | .push(OP_SPLIT)
215 | .push(OP_TUCK)
216 | .push(OP_CAT)
217 | .apply(decodeUint)
218 | }
219 |
220 | // Pushes the secp256k1 order onto the stack
221 | function pushOrder() {
222 | this.script
223 | .push(ORDER_PREFIX)
224 | .push(asm('00 OP_15 OP_NUM2BIN OP_INVERT OP_CAT 00 OP_CAT'))
225 | }
226 |
227 | // Divides the order by 2
228 | function divOrder() {
229 | this.script.push(asm('OP_DUP OP_2 OP_DIV'))
230 | }
231 |
232 | // Is the sighash MSB 0x00 or 0xFF
233 | function sighashMSBis0or255() {
234 | this.script
235 | .push(asm('OP_ROT OP_3 OP_ROLL OP_DUP ff OP_EQUAL OP_SWAP 00 OP_EQUAL OP_BOOLOR OP_TUCK'))
236 | }
237 |
238 | // Is the sighash mod greater than the secp256k1 order
239 | function sighashModGtOrder() {
240 | this.script.push(
241 | asm('OP_3 OP_ROLL OP_TUCK OP_MOD OP_DUP OP_4 OP_ROLL OP_GREATERTHAN')
242 | )
243 | }
244 |
245 | // Constructs and pushes the signature onto the stack
246 | function pushSig() {
247 | this.script
248 | .push(SIG_PREFIX)
249 | .push(OP_SWAP)
250 | .apply(reverse, [32])
251 | .push(OP_CAT)
252 | .push([SIGHASH_FLAG])
253 | .push(OP_CAT)
254 | }
255 |
256 | /**
257 | * Assuming the top stack item is a Tx Preimage, creates and verifies a
258 | * signature with `OP_CHECKSIG`.
259 | *
260 | * This uses the {@link https://xiaohuiliu.medium.com/optimal-op-push-tx-ded54990c76f optimal OP_PUSH_TX approach}
261 | * which compiles to 87 bytes (compared to 438 as per {@link checkTx}).
262 | *
263 | * However, due to the {@link https://bitcoin.stackexchange.com/questions/85946/low-s-value-in-bitcoin-signature Low-S Constraint}
264 | * the most significant byte of the sighash must be less than a theshold of
265 | * `0x7E`. There is a roughly 50% chance the signature being invalid. Therefore,
266 | * when using this technique it is necessary to check the preimage and if
267 | * necessary continue to malleate the transaction until it is valid.
268 | *
269 | * @returns {void}
270 | */
271 | export function checkTxOpt() {
272 | this.script
273 | .push(OP_HASH256)
274 | .apply(add1ToHash)
275 | .apply(pushSigOpt)
276 | .push(PUBKEY_OPT)
277 | .push(OP_CHECKSIG)
278 | }
279 |
280 | /**
281 | * As {@link checkTxOpt} but verifies the signature with `OP_CHECKSIGVERIFY`.
282 | *
283 | * @returns {void}
284 | */
285 | export function checkTxOptVerify() {
286 | this.script.apply(checkTxOpt)
287 | this.script.cells.pop()
288 | this.script.push(OP_CHECKSIGVERIFY)
289 | }
290 |
291 | // Adds 1 to the sighash MSB
292 | function add1ToHash() {
293 | this.script.push(
294 | asm('OP_1 OP_SPLIT OP_SWAP OP_BIN2NUM OP_1ADD OP_SWAP OP_CAT')
295 | )
296 | }
297 |
298 | // Constructs and pushes the signature onto the stack (optimal version)
299 | function pushSigOpt() {
300 | this.script
301 | .push(SIG_PREFIX)
302 | .push(OP_SWAP)
303 | .push(OP_CAT)
304 | .push([SIGHASH_FLAG])
305 | .push(OP_CAT)
306 | }
307 |
--------------------------------------------------------------------------------
/src/macros/sign-tx.js:
--------------------------------------------------------------------------------
1 | import nimble from '@runonbitcoin/nimble'
2 |
3 | const { sighashFlags } = nimble.constants
4 | const { generateTxSignature } = nimble.functions
5 | const { ecdsaSignWithK, encodeDER, sighash } = nimble.functions
6 |
7 | /**
8 | * Signs the transaction context and pushes the signature onto the script.
9 | *
10 | * If no tx context is available then 71 bytes of zeros are pushed onto the
11 | * script instead.
12 | *
13 | * @param {nimble.PrivateKey} privkey Private key
14 | * @returns {void}
15 | */
16 | export function signTx(privkey) {
17 | // If ctx, create signature, otherwise empty 71 bytes
18 | const sig = this.ctx ?
19 | generateTxSignature(
20 | this.ctx.tx,
21 | this.ctx.vin,
22 | this.utxo.script,
23 | this.utxo.satoshis,
24 | privkey.number,
25 | privkey.toPublicKey().point,
26 | this.opts.sighashFlags || sighashFlags.SIGHASH_ALL
27 | ) :
28 | new Uint8Array(71);
29 |
30 | this.script.push(sig)
31 | }
32 |
33 | /**
34 | * As {@link signTx} but can be passed a K which is used in the signature
35 | * generation.
36 | *
37 | * @param {nimble.PrivateKey} privkey Private key
38 | * @param {Uint8Array} k K value
39 | * @returns {void}
40 | */
41 | export function signTxWithK(privkey, k) {
42 | // If ctx, create signature, otherwise empty 71 bytes
43 | const sig = this.ctx ?
44 | generateTxSigWithK(
45 | this.ctx.tx,
46 | this.ctx.vin,
47 | this.utxo.script,
48 | this.utxo.satoshis,
49 | privkey,
50 | k,
51 | this.opts.sighashFlags || sighashFlags.SIGHASH_ALL
52 | ) :
53 | new Uint8Array(71);
54 |
55 | this.script.push(sig)
56 | }
57 |
58 | // Generates the tx signature with custom K value
59 | function generateTxSigWithK(tx, vin, script, satoshis, privkey, k, flags) {
60 | const hash = sighash(tx, vin, script, satoshis, flags)
61 | const sig = ecdsaSignWithK(hash, k, privkey.number, privkey.toPublicKey().point)
62 | return Array.from([...encodeDER(sig), flags])
63 | }
64 |
--------------------------------------------------------------------------------
/src/macros/varint.js:
--------------------------------------------------------------------------------
1 | import nimble from '@runonbitcoin/nimble'
2 | import { decodeUint, trim } from './binary.js'
3 | import { num } from '../helpers/index.js'
4 |
5 | const {
6 | OP_1,
7 | OP_DROP,
8 | OP_DUP,
9 | OP_ELSE,
10 | OP_ENDIF,
11 | OP_EQUAL,
12 | OP_IF,
13 | OP_NIP,
14 | OP_SPLIT,
15 | OP_SWAP
16 | } = nimble.constants.opcodes
17 |
18 | /**
19 | * Assuming the top stack item is a VarInt encoded byte vector, the VarInt is
20 | * copied and placed on top of the stack as a ScriptNum.
21 | *
22 | * The original element is not removed.
23 | *
24 | * Use this function if you would like to to extract the VarInt number, yet
25 | * leave the original data on the stack.
26 | *
27 | * @returns {void}
28 | */
29 | export function getVarint() {
30 | this.script
31 | .push(OP_DUP)
32 | .apply(varintSwitch, [doGetVarint])
33 | }
34 |
35 | // Extract and decode the VarInt number
36 | function doGetVarint(bytes) {
37 | if (bytes === 1) {
38 | this.script.push(OP_NIP)
39 |
40 | } else {
41 | this.script
42 | .push(OP_DROP)
43 | .push(num(bytes))
44 | .push(OP_SPLIT)
45 | .push(OP_DROP)
46 | }
47 |
48 | this.script.apply(decodeUint)
49 | }
50 |
51 | /**
52 | * Assuming the top stack item is a VarInt encoded byte vector, the VarInt
53 | * is extracted and placed on top of the stack as a ScriptNum.
54 | *
55 | * The original element is removed and any remaining data is second on the
56 | * stack.
57 | *
58 | * Use this function if the VarInt is part of a larger string of bytes and you
59 | * would like to extract the data whilst retaining the remaining bytes.
60 | *
61 | * @returns {void}
62 | */
63 | export function readVarint() {
64 | this.script.apply(varintSwitch, [doReadVarint])
65 | }
66 |
67 | // Extract the VarInt data and place on top
68 | function doReadVarint(bytes) {
69 | if (bytes > 1) {
70 | this.script
71 | .push(OP_DROP)
72 | .push(num(bytes))
73 | .push(OP_SPLIT)
74 | .push(OP_SWAP)
75 | }
76 |
77 | this.script
78 | .apply(decodeUint)
79 | .push(OP_SPLIT)
80 | .push(OP_SWAP)
81 | }
82 |
83 | /**
84 | * Assuming the top stack item is a VarInt encoded binary, the VarInt prefix
85 | * is trimmed from the leading bytes and the encoded data is placed on top of
86 | * the stack.
87 | *
88 | * The original element is removed.
89 | *
90 | * Use this function if you would like to cleanly trim the VarInt number from
91 | * the encoded data.
92 | *
93 | * @returns {void}
94 | */
95 | export function trimVarint() {
96 | this.script.apply(varintSwitch, [doTrimVarint])
97 | }
98 |
99 | // Trim varint from leading bytes
100 | function doTrimVarint(bytes) {
101 | this.script.push(OP_DROP)
102 |
103 | if (bytes > 1) {
104 | this.script.apply(trim, [bytes])
105 | }
106 | }
107 |
108 | // Shared VarInt switch statement
109 | function varintSwitch(handleVarint) {
110 | this.script
111 | .push(OP_1)
112 | .push(OP_SPLIT)
113 | .push(OP_SWAP)
114 | .push(OP_DUP)
115 | .push([253])
116 | .push(OP_EQUAL)
117 | .push(OP_IF)
118 | .apply(handleVarint, [2])
119 | .push(OP_ELSE)
120 | .push(OP_DUP)
121 | .push([254])
122 | .push(OP_EQUAL)
123 | .push(OP_IF)
124 | .apply(handleVarint, [4])
125 | .push(OP_ELSE)
126 | .push(OP_DUP)
127 | .push([255])
128 | .push(OP_EQUAL)
129 | .push(OP_IF)
130 | .apply(handleVarint, [8])
131 | .push(OP_ELSE)
132 | .apply(handleVarint, [1])
133 | .push(OP_ENDIF)
134 | .push(OP_ENDIF)
135 | .push(OP_ENDIF)
136 | }
137 |
--------------------------------------------------------------------------------
/test/casts/opreturn.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import { casts } from '../../src/index.js'
3 |
4 | const { OpReturn } = casts
5 |
6 | test('OpReturn.lock() takes a single data binary parameter', t => {
7 | const cast = OpReturn.lock(0, { data: 'hello world' })
8 | const output = cast.toOutput()
9 | const script = cast.toScript()
10 |
11 | t.is(output.satoshis, 0)
12 | t.deepEqual(output.script, script)
13 | t.regex(script.toASM(), /^0 OP_RETURN [0-9a-f]{22}$/)
14 | })
15 |
16 | test('OpReturn.lock() takes a list of data binary parameters', t => {
17 | const cast = OpReturn.lock(0, { data: ['hello', 'world'] })
18 | const script = cast.toScript()
19 |
20 | t.regex(script.toASM(), /^0 OP_RETURN [0-9a-f]{10} [0-9a-f]{10}$/)
21 | })
22 |
23 | test('OpReturn.lock() takes a mixed list of parameters', t => {
24 | const cast = OpReturn.lock(0, { data: ['hello', 'world', { opcode: 90 }, [0,1,2,3]] })
25 | const script = cast.toScript()
26 |
27 | t.regex(script.toASM(), /^0 OP_RETURN [0-9a-f]{10} [0-9a-f]{10} OP_10 00010203$/)
28 | })
29 |
--------------------------------------------------------------------------------
/test/casts/p2ms.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import nimble from '@runonbitcoin/nimble'
3 | import { casts, toUTXO } from '../../src/index.js'
4 |
5 | const { P2MS } = casts
6 | const keys = new Array(3).fill(0).map(_ => nimble.PrivateKey.fromRandom())
7 | const pubkeys = keys.map(k => k.toPublicKey())
8 | const privkeys = keys.slice(0, 2)
9 | const utxo = toUTXO({
10 | txid: '0000000000000000000000000000000000000000000000000000000000000000',
11 | vout: 0
12 | })
13 |
14 | test('P2MS.lock() locks satoshis to a threshold of pubkeys', t => {
15 | const cast = P2MS.lock(1000, { pubkeys, threshold: 2 })
16 | const output = cast.toOutput()
17 | const script = cast.toScript()
18 |
19 | t.is(output.satoshis, 1000)
20 | t.deepEqual(output.script, script)
21 | t.regex(script.toASM(), /^OP_2 ([0-9a-f]{66} ?){3} OP_3 OP_CHECKMULTISIG$/)
22 | })
23 |
24 | test('P2MS.lock() throws if arguments invalid', t => {
25 | t.throws(() => P2MS.lock(1000, {}))
26 | t.throws(() => P2MS.lock(1000, { pubkeys: ['Not a pubkey'], threshold: 1 }))
27 | t.throws(() => P2MS.lock(1000, { pubkeys, threshold: 'xyz' }))
28 | })
29 |
30 | test('P2MS.unlock() unlocks UTXO with privkeys', t => {
31 | const cast = P2MS.unlock(utxo, { privkeys })
32 | const input = cast.toInput()
33 | const script = cast.toScript()
34 |
35 | t.is(input.txid, utxo.txid)
36 | t.is(input.vout, utxo.vout)
37 | t.deepEqual(input.script, script)
38 | t.regex(script.toASM(), /^0 (0{142} ?){2}$/)
39 | })
40 |
41 | test('P2MS.unlock() throws if arguments invalid', t => {
42 | t.throws(() => P2MS.unlock(utxo, {}))
43 | t.throws(() => P2MS.unlock(utxo, { privkeys: ['a', 'b']}))
44 | })
45 |
46 | test('P2MS.simulate() evaluates as valid if signed with threshold of keys', t => {
47 | const vm = P2MS.simulate({ pubkeys, threshold: 2 }, { privkeys })
48 | t.true(vm.success)
49 | })
50 |
51 | test('P2MS.simulate() evaluates as invalid if signed with insufficient threshold of keys', t => {
52 | const vm = P2MS.simulate({ pubkeys, threshold: 2 }, { privkeys: [privkeys[0]] })
53 | t.false(vm.success)
54 | t.truthy(vm.error)
55 | })
56 |
57 | test('P2MS.simulate() evaluates as invalid if signed with incorrect of keys', t => {
58 | const wrongKeys = new Array(2).fill(0).map(_ => nimble.PrivateKey.fromRandom())
59 | const vm = P2MS.simulate({ pubkeys, threshold: 2 }, { privkeys: wrongKeys })
60 | t.false(vm.success)
61 | t.truthy(vm.error)
62 | })
63 |
--------------------------------------------------------------------------------
/test/casts/p2pk.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import nimble from '@runonbitcoin/nimble'
3 | import { casts, toUTXO } from '../../src/index.js'
4 |
5 | const { P2PK } = casts
6 | const privkey = nimble.PrivateKey.fromRandom()
7 | const pubkey = privkey.toPublicKey()
8 | const utxo = toUTXO({
9 | txid: '0000000000000000000000000000000000000000000000000000000000000000',
10 | vout: 0
11 | })
12 |
13 | test('P2PK.lock() locks satoshis to a pubkey', t => {
14 | const cast = P2PK.lock(1000, { pubkey })
15 | const output = cast.toOutput()
16 | const script = cast.toScript()
17 |
18 | t.is(output.satoshis, 1000)
19 | t.deepEqual(output.script, script)
20 | t.regex(script.toASM(), /^[0-9a-f]{66} OP_CHECKSIG$/)
21 | })
22 |
23 | test('P2PK.lock() throws if arguments invalid', t => {
24 | t.throws(() => P2PK.lock(1000, {}))
25 | t.throws(() => P2PK.lock(1000, { pubkey: 'Not a pubkey' }))
26 | })
27 |
28 | test('P2PK.unlock() unlocks UTXO with given privkey', t => {
29 | const cast = P2PK.unlock(utxo, { privkey })
30 | const input = cast.toInput()
31 | const script = cast.toScript()
32 |
33 | t.is(input.txid, utxo.txid)
34 | t.is(input.vout, utxo.vout)
35 | t.deepEqual(input.script, script)
36 | t.regex(script.toASM(), /^0{142}$/)
37 | })
38 |
39 | test('P2PK.unlock() throws if arguments invalid', t => {
40 | t.throws(() => P2PK.unlock(utxo, {}))
41 | t.throws(() => P2PK.unlock(utxo, { privkey: 'Not a privkey' }))
42 | })
43 |
44 | test('P2PK.simulate() evaluates as valid if signed with correct key', t => {
45 | const vm = P2PK.simulate({ pubkey }, { privkey })
46 | t.true(vm.success)
47 | })
48 |
49 | test('P2PK.simulate() evaluates as invalid if signed with incorrect key', t => {
50 | const wrongKey = nimble.PrivateKey.fromRandom()
51 | const vm = P2PK.simulate({ pubkey }, { privkey: wrongKey })
52 | t.false(vm.success)
53 | t.truthy(vm.error)
54 | })
55 |
--------------------------------------------------------------------------------
/test/casts/p2pkh.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import nimble from '@runonbitcoin/nimble'
3 | import { casts, toUTXO } from '../../src/index.js'
4 |
5 | const { P2PKH } = casts
6 | const privkey = nimble.PrivateKey.fromRandom()
7 | const address = privkey.toPublicKey().toAddress()
8 | const utxo = toUTXO({
9 | txid: '0000000000000000000000000000000000000000000000000000000000000000',
10 | vout: 0
11 | })
12 |
13 | test('P2PKH.lock() locks satoshis to an address', t => {
14 | const cast = P2PKH.lock(1000, { address })
15 | const output = cast.toOutput()
16 | const script = cast.toScript()
17 |
18 | t.is(output.satoshis, 1000)
19 | t.deepEqual(output.script, script)
20 | t.regex(script.toASM(), /^OP_DUP OP_HASH160 [0-9a-f]{40} OP_EQUALVERIFY OP_CHECKSIG$/)
21 | })
22 |
23 | test('P2PKH.lock() accepts address as string', t => {
24 | t.notThrows(() => P2PKH.lock(1000, { address: address.toString() }))
25 | })
26 |
27 | test('P2PKH.lock() throws if arguments invalid', t => {
28 | t.throws(() => P2PKH.lock(1000, {}))
29 | t.throws(() => P2PKH.lock(1000, { address: 'Not an address' }))
30 | })
31 |
32 | test('P2PKH.unlock() unlocks UTXO with a privkey', t => {
33 | const cast = P2PKH.unlock(utxo, { privkey })
34 | const input = cast.toInput()
35 | const script = cast.toScript()
36 |
37 | t.is(input.txid, utxo.txid)
38 | t.is(input.vout, utxo.vout)
39 | t.deepEqual(input.script, script)
40 | t.regex(script.toASM(), /^0{142} [0-9a-f]{66}$/)
41 | })
42 |
43 | test('P2PKH.unlock() throws if arguments invalid', t => {
44 | t.throws(() => P2PKH.unlock(utxo, {}))
45 | t.throws(() => P2PKH.unlock(utxo, { privkey: 'Not a privkey' }))
46 | })
47 |
48 | test('P2PKH.simulate() evaluates as valid if signed with correct key', t => {
49 | const vm = P2PKH.simulate({ address }, { privkey })
50 | t.true(vm.success)
51 | })
52 |
53 | test('P2PKH.simulate() throws when signed with incorrect key', t => {
54 | const wrongKey = nimble.PrivateKey.fromRandom()
55 | const vm = P2PKH.simulate({ address }, { privkey: wrongKey })
56 | t.false(vm.success)
57 | t.truthy(vm.error)
58 | })
59 |
--------------------------------------------------------------------------------
/test/casts/p2rph.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import nimble from '@runonbitcoin/nimble'
3 | import { casts, toUTXO } from '../../src/index.js'
4 | import { generateK, calculateR } from '../../src/extra/r-puzzle.js'
5 |
6 | const { decodeHex, encodeHex, isBuffer } = nimble.functions
7 | const { P2RPH } = casts
8 | const k = generateK()
9 | const r = calculateR(k)
10 | const privkey = nimble.PrivateKey.fromRandom()
11 | const utxo = toUTXO({
12 | txid: '0000000000000000000000000000000000000000000000000000000000000000',
13 | vout: 0
14 | })
15 |
16 | test('generateK() returns random 32 bytes', t => {
17 | const k = generateK()
18 | t.true(isBuffer(k))
19 | t.is(k.length, 32)
20 | })
21 |
22 | test('calculateR() returns R from K', t => {
23 | // Example taken from elixir tests
24 | const myK = '5c5fe3d59de129819770b3d91a6a5422f8cbb7c28f27a532de1efbc7c4ffb5d6'
25 | const myR = '00906367a7db162403eda7181c5270e9d86beee89d0886a1fe44238fcfbe9cabd3'
26 |
27 | const r = calculateR(decodeHex(myK))
28 | t.true(isBuffer(r))
29 | t.is(encodeHex(r), myR)
30 | })
31 |
32 | test('P2RPH.lock() locks satoshis to an R value', t => {
33 | const cast = P2RPH.lock(1000, { r })
34 | const output = cast.toOutput()
35 | const script = cast.toScript()
36 |
37 | t.is(output.satoshis, 1000)
38 | t.deepEqual(output.script, script)
39 | t.regex(script.toASM(), /^OP_OVER OP_3 OP_SPLIT OP_NIP OP_1 OP_SPLIT OP_SWAP OP_SPLIT OP_DROP OP_HASH160 [0-9a-f]{40} OP_EQUALVERIFY OP_TUCK OP_CHECKSIGVERIFY OP_CHECKSIG$/)
40 | })
41 |
42 | test('P2RPH.lock() throws if arguments invalid', t => {
43 | t.throws(() => P2RPH.lock(1000, {}))
44 | t.throws(() => P2RPH.lock(1000, { r: 'Not a buffer' }))
45 | t.throws(() => P2RPH.lock(1000, { r: [0, 1, 2, 3, 4] }))
46 | })
47 |
48 | test('P2RPH.unlock() unlocks UTXO with given K value', t => {
49 | const cast = P2RPH.unlock(utxo, { k, privkey })
50 | const input = cast.toInput()
51 | const script = cast.toScript()
52 |
53 | t.is(input.txid, utxo.txid)
54 | t.is(input.vout, utxo.vout)
55 | t.deepEqual(input.script, script)
56 | t.regex(script.toASM(), /^(0{142} ?){2} [0-9a-f]{66}$/)
57 | })
58 |
59 | test('P2RPH.unlock() signs with random k if none given', t => {
60 | const cast = P2RPH.unlock(utxo, { k })
61 | const script = cast.toScript()
62 | t.regex(script.toASM(), /^(0{142} ?){2} [0-9a-f]{66}$/)
63 | })
64 |
65 | test('P2RPH.unlock() throws if arguments invalid', t => {
66 | t.throws(() => P2RPH.unlock(utxo, {}))
67 | t.throws(() => P2RPH.unlock(utxo, { k: 'Not a buffer' }))
68 | t.throws(() => P2RPH.unlock(utxo, { k: [0, 1, 2, 3, 4] }))
69 | })
70 |
71 | test('P2RPH.simulate() evaluates as valid with correct K', t => {
72 | const vm1 = P2RPH.simulate({ r }, { k, privkey })
73 | const vm2 = P2RPH.simulate({ r }, { k })
74 | t.true(vm1.success)
75 | t.true(vm2.success)
76 | })
77 |
78 | test('P2RPH.simulate() evaluates as invalid with incorrect K', t => {
79 | const wrongK = generateK()
80 | const vm = P2RPH.simulate({ r }, { k: wrongK })
81 | t.false(vm.success)
82 | t.truthy(vm.error)
83 | })
84 |
--------------------------------------------------------------------------------
/test/casts/raw.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import nimble from '@runonbitcoin/nimble'
3 | import { casts, toUTXO } from '../../src/index.js'
4 |
5 | const { Raw } = casts
6 | const lockScript = nimble.Script.fromHex('76a914a58621fd80c3abcf4f81d343f6a78dc891082d6688ac')
7 | const unlockScript = nimble.Script.fromHex('47304402205832ed8192e83d640824c021107024f9f03adf1fcc9bca826025ab1ce9f012b9022005d71b00d40023a6bb8a2644f7f599bf367850a1ec5ddc95882c9841a1867c6a412102554669f32b842ec626175d3b5380a335213506d55aa896f04d66d9f46f48cf18')
8 | const utxo = toUTXO({
9 | txid: '0000000000000000000000000000000000000000000000000000000000000000',
10 | vout: 0
11 | })
12 |
13 | test('Raw.lock() locks satoshis to an script', t => {
14 | const cast = Raw.lock(1000, { script: lockScript })
15 | const output = cast.toOutput()
16 | const script = cast.toScript()
17 |
18 | t.is(output.satoshis, 1000)
19 | t.deepEqual(output.script, script)
20 | t.regex(script.toASM(), /^OP_DUP OP_HASH160 [0-9a-f]{40} OP_EQUALVERIFY OP_CHECKSIG$/)
21 | })
22 |
23 | test('Raw.lock() accepts script as string', t => {
24 | t.notThrows(() => Raw.lock(1000, { script: lockScript.toHex() }))
25 | })
26 |
27 | test('Raw.lock() throws if arguments invalid', t => {
28 | t.throws(() => Raw.lock(1000, {}))
29 | t.throws(() => Raw.lock(1000, { script: 'Not a script' }))
30 | })
31 |
32 | test('Raw.unlock() unlocks UTXO with a privkey', t => {
33 | const cast = Raw.unlock(utxo, { script: unlockScript })
34 | const input = cast.toInput()
35 | const script = cast.toScript()
36 |
37 | t.is(input.txid, utxo.txid)
38 | t.is(input.vout, utxo.vout)
39 | t.deepEqual(input.script, script)
40 | t.regex(script.toASM(), /^[0-9a-f]{142} [0-9a-f]{66}$/)
41 | })
42 |
43 | test('Raw.unlock() throws if arguments invalid', t => {
44 | t.throws(() => Raw.unlock(utxo, {}))
45 | t.throws(() => Raw.unlock(utxo, { script: 'Not a script' }))
46 | })
47 |
--------------------------------------------------------------------------------
/test/classes/cast.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import nimble from '@runonbitcoin/nimble'
3 | import { Cast, isCast, toUTXO } from '../../src/index.js'
4 |
5 | const { Transaction, Script } = nimble.classes
6 | const { opcodes } = nimble.constants
7 | const { sha256, sha256d } = nimble.functions
8 |
9 | class HashPuzzle extends Cast {
10 | lockingScript({ secret }) {
11 | this.script
12 | .push(opcodes.OP_SHA256)
13 | .push(sha256d(secret))
14 | .push(opcodes.OP_EQUAL)
15 | }
16 |
17 | unlockingScript({ secret }) {
18 | this.script.push(sha256(secret))
19 | }
20 | }
21 |
22 | const secret = 'test secret'
23 |
24 | test('Cast#lock() creates a locking Cast', t => {
25 | const cast = HashPuzzle.lock(1000, { secret })
26 | t.true(isCast(cast))
27 | t.is(cast.mode, 'lock')
28 | t.is(cast.satoshis, 1000)
29 | })
30 |
31 | test('Cast#unlock() creates an unlocking Cast', t => {
32 | const utxo = toUTXO({
33 | txid: '0000000000000000000000000000000000000000000000000000000000000000',
34 | vout: 0
35 | })
36 | const cast = HashPuzzle.unlock(utxo, { secret })
37 | t.true(isCast(cast))
38 | t.is(cast.mode, 'unlock')
39 | t.is(cast.utxo.txid, '0000000000000000000000000000000000000000000000000000000000000000')
40 | t.is(cast.utxo.vout, 0)
41 | })
42 |
43 | test('Cast#simulate() returns vm with valid params', t => {
44 | const vm = HashPuzzle.simulate({ secret }, { secret })
45 | t.true(vm.success)
46 | t.is(vm.error, null)
47 | t.true(Array.isArray(vm.chunks))
48 | t.true(Array.isArray(vm.stack))
49 | t.true(Array.isArray(vm.stackTrace))
50 | })
51 |
52 | test('Cast#simulate() returns vm with unvalid params', t => {
53 | const vm = HashPuzzle.simulate({ secret }, { secret: 'incorrect' })
54 | t.false(vm.success)
55 | t.true(vm.error instanceof Error)
56 | })
57 |
58 | test('Cast#toScript() returns the script', t => {
59 | const cast = HashPuzzle.lock(1000, { secret })
60 | const script = cast.toScript()
61 | t.true(script instanceof Script)
62 | t.is(script.chunks.length, 3)
63 | })
64 |
65 | test('Cast#toOutput() returns the Output', t => {
66 | const cast = HashPuzzle.lock(1000, { secret })
67 | const output = cast.toOutput()
68 | t.true(output instanceof Transaction.Output)
69 | t.is(output.satoshis, 1000)
70 | })
71 |
72 | test('Cast#toOutput() throws if unlocking cast', t => {
73 | const utxo = toUTXO({
74 | txid: '0000000000000000000000000000000000000000000000000000000000000000',
75 | vout: 0
76 | })
77 | const cast = HashPuzzle.unlock(utxo, { secret })
78 | t.throws(_ => cast.toOutput())
79 | })
80 |
81 | test('Cast#toInput() returns the Output', t => {
82 | const utxo = toUTXO({
83 | txid: '0000000000000000000000000000000000000000000000000000000000000000',
84 | vout: 0
85 | })
86 | const cast = HashPuzzle.unlock(utxo, { secret })
87 | const input = cast.toInput()
88 | t.true(input instanceof Transaction.Input)
89 | t.is(input.txid, utxo.txid)
90 | t.is(input.vout, utxo.vout)
91 | })
92 |
93 | test('Cast#toInput() throws if locking cast', t => {
94 | const cast = HashPuzzle.lock(1000, { secret })
95 | t.throws(_ => cast.toInput())
96 | })
97 |
--------------------------------------------------------------------------------
/test/classes/forge.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import fs from 'fs'
3 | import nimble from '@runonbitcoin/nimble'
4 | import { Forge, casts, createForge, toUTXO, forgeTx } from '../../src/index.js'
5 |
6 | const path = new URL('../vectors/bip69.json', import.meta.url).pathname
7 | const bip69 = JSON.parse(fs.readFileSync(path))
8 |
9 | const { P2PK, P2PKH, OpReturn, Raw } = casts
10 | const privkey = nimble.PrivateKey.fromRandom()
11 | const pubkey = privkey.toPublicKey()
12 | const address = pubkey.toAddress()
13 | const utxo = {
14 | txid: '0000000000000000000000000000000000000000000000000000000000000000',
15 | vout: 0
16 | }
17 |
18 | test('forge.inputSum gets sum of all inputs', t => {
19 | const forge = new Forge()
20 | t.is(forge.inputSum, 0)
21 |
22 | forge.addInput(P2PK.unlock(toUTXO({ satoshis: 150 }), { privkey }))
23 | forge.addInput(P2PK.unlock(toUTXO({ satoshis: 9500 }), { privkey }))
24 | t.is(forge.inputSum, 9650)
25 | })
26 |
27 | test('forge.outputSum gets sum of all outputs', t => {
28 | const forge = new Forge()
29 | t.is(forge.outputSum, 0)
30 |
31 | forge.addOutput(P2PK.lock(150, { pubkey }))
32 | forge.addOutput(P2PK.lock(7735, { pubkey }))
33 | t.is(forge.outputSum, 7885)
34 | })
35 |
36 | test('forge.addInput() adds input casts to forge', t => {
37 | const forge = new Forge()
38 | t.is(forge.inputs.length, 0)
39 |
40 | forge.addInput(P2PK.unlock(toUTXO(), { privkey }))
41 | forge.addInput(P2PK.unlock(toUTXO(), { privkey }))
42 | t.is(forge.inputs.length, 2)
43 | })
44 |
45 | test('forge.addInput() accepts array of casts', t => {
46 | const forge = new Forge()
47 | t.is(forge.inputs.length, 0)
48 |
49 | forge.addInput([
50 | P2PK.unlock(toUTXO(), { privkey }),
51 | P2PK.unlock(toUTXO(), { privkey })
52 | ])
53 | t.is(forge.inputs.length, 2)
54 | })
55 |
56 | test('forge.addInput() throws if invalid value given', t => {
57 | const forge = new Forge()
58 |
59 | t.throws(() => forge.addInput('not a cast'))
60 | t.throws(() => forge.addInput(P2PK.lock(150, { pubkey })))
61 | })
62 |
63 | test('forge.addOutput() adds output casts to forge', t => {
64 | const forge = new Forge()
65 | t.is(forge.outputs.length, 0)
66 |
67 | forge.addOutput(P2PK.lock(150, { pubkey }))
68 | forge.addOutput(P2PK.lock(150, { pubkey }))
69 | t.is(forge.outputs.length, 2)
70 | })
71 |
72 | test('forge.addOutput() accepts array of casts', t => {
73 | const forge = new Forge()
74 | t.is(forge.outputs.length, 0)
75 |
76 | forge.addOutput([
77 | P2PK.lock(150, { pubkey }),
78 | P2PK.lock(150, { pubkey })
79 | ])
80 | t.is(forge.outputs.length, 2)
81 | })
82 |
83 | test('forge.addOutput() throws if invalid value given', t => {
84 | const forge = new Forge()
85 |
86 | t.throws(() => forge.addOutput('not a cast'))
87 | t.throws(() => forge.addOutput(P2PK.unlock(toUTXO(), { privkey })))
88 | })
89 |
90 | test('forge.changeTo() sets changeScript to any given class and params', t => {
91 | const forge = new Forge()
92 | forge.changeTo(P2PK, { pubkey })
93 |
94 | t.true(forge.changeScript instanceof nimble.Script)
95 | t.is(forge.changeScript.length, 35)
96 | })
97 |
98 | test('forge.changeTo() accepts P2PKH params as sensible default', t => {
99 | const forge = new Forge()
100 | forge.changeTo({ address })
101 | t.true(forge.changeScript instanceof nimble.Script)
102 | t.is(forge.changeScript.length, 25)
103 | })
104 |
105 | test('forge.changeTo() accepts Raw params as sensible default', t => {
106 | const forge = new Forge()
107 | forge.changeTo({ script: 'OP_TRUE' })
108 | t.true(forge.changeScript instanceof nimble.Script)
109 | t.is(forge.changeScript.length, 1)
110 | })
111 |
112 | test('forge.changeTo() throws error if invalid cast params given', t => {
113 | const forge = new Forge()
114 | t.throws(_ => forge.changeTo({ foo: 'bar' }))
115 | })
116 |
117 | function assertBetween(val, min, max) {
118 | if (val < min || val > max) {
119 | throw new Error(`value not within range: ${val} != ${min} < ${max}`)
120 | }
121 | }
122 |
123 | test('forge.calcRequiredFee() calculates the required fee for the tx', t => {
124 | const forge = new Forge({
125 | inputs: [
126 | P2PK.unlock(toUTXO({...utxo, satoshis: 10000, script: '01'}), { privkey })
127 | ],
128 | outputs: [
129 | P2PK.lock(5000, { pubkey }),
130 | P2PK.lock(1000, { pubkey })
131 | ]
132 | })
133 |
134 | const bytes = forge.toTx().toBuffer().length
135 | t.is(forge.calcRequiredFee(), Math.ceil(bytes / 20))
136 | assertBetween(forge.calcRequiredFee(1000), bytes-1, bytes+1)
137 | t.pass()
138 | })
139 |
140 | test('forge.calcRequiredFee() calculates data scripts separately', t => {
141 | const forge = new Forge({
142 | outputs: [
143 | OpReturn.lock(0, { data: new Uint8Array(1000) })
144 | ]
145 | })
146 |
147 | const bytes = forge.toTx().toBuffer().length
148 | t.is(forge.calcRequiredFee(1000), bytes)
149 | t.is(forge.calcRequiredFee({ standard: 1000, data: 100}), bytes-914)
150 | t.pass()
151 | })
152 |
153 | test('forge.sort() sorts inputs as per bip69', t => {
154 | for (let v of bip69.inputs) {
155 | const inputs = v.inputs.map(i => {
156 | const utxo = toUTXO({ txid: i.txId, vout: i.vout })
157 | return P2PK.unlock(utxo, { privkey })
158 | })
159 |
160 | const forge = new Forge({ inputs }).sort()
161 | const indexes = forge.inputs.map(i => inputs.indexOf(i))
162 | t.deepEqual(indexes, v.expected, v.description)
163 | }
164 | })
165 |
166 | test('forge.sort() sorts outputs as per bip69', t => {
167 | for (let v of bip69.outputs) {
168 | const outputs = v.outputs.map(o => {
169 | return Raw.lock(o.value, { script: o.script })
170 | })
171 |
172 | const forge = new Forge({ outputs }).sort()
173 | const indexes = forge.outputs.map(i => outputs.indexOf(i))
174 | t.deepEqual(indexes, v.expected, v.description)
175 | }
176 | })
177 |
178 | test('forge.toTx() returns signed tx', t => {
179 | const forge = new Forge({
180 | inputs: [
181 | P2PK.unlock(toUTXO({...utxo, satoshis: 10000, script: '01'}), { privkey })
182 | ],
183 | outputs: [
184 | P2PK.lock(5000, { pubkey }),
185 | P2PK.lock(1000, { pubkey })
186 | ]
187 | })
188 |
189 | const tx = forge.toTx()
190 | t.true(tx instanceof nimble.Transaction)
191 | t.is(tx.outputs.length, 2)
192 | t.is(tx.fee, 4000)
193 | })
194 |
195 | test('forge.toTx() returns signed tx with change', t => {
196 | const forge = new Forge({
197 | inputs: [
198 | P2PK.unlock(toUTXO({...utxo, satoshis: 10000, script: '01'}), { privkey })
199 | ],
200 | outputs: [
201 | P2PK.lock(5000, { pubkey }),
202 | P2PK.lock(1000, { pubkey })
203 | ],
204 | change: { address }
205 | })
206 |
207 | const tx = forge.toTx()
208 | t.is(tx.outputs.length, 3)
209 | t.is(tx.outputs[2].satoshis, 3987)
210 | t.is(tx.fee, 13)
211 | })
212 |
213 | test('createForge() sets given inputs and outputs', t => {
214 | const forge = createForge({
215 | inputs: [
216 | P2PKH.unlock(toUTXO(), { privkey }),
217 | P2PK.unlock(toUTXO(), { privkey })
218 | ],
219 | outputs: [
220 | P2PKH.lock(10000, { address }),
221 | P2PK.lock(10000, { pubkey }),
222 | OpReturn.lock(0, { data: 'hello world' })
223 | ]
224 | })
225 |
226 | t.is(forge.inputs.length, 2)
227 | t.is(forge.outputs.length, 3)
228 | t.is(forge.outputSum, 20000)
229 | })
230 |
231 | test('createForge() sets given change param tuple', t => {
232 | const forge = createForge({
233 | change: [P2PK, { pubkey }]
234 | })
235 |
236 | t.true(forge.changeScript instanceof nimble.Script)
237 | t.is(forge.changeScript.length, 35)
238 | })
239 |
240 | test('createForge() sets given change param as P2PKH script', t => {
241 | const forge = createForge({
242 | change: { address }
243 | })
244 |
245 | t.true(forge.changeScript instanceof nimble.Script)
246 | t.is(forge.changeScript.length, 25)
247 | })
248 |
249 | test('createForge() sets given change param as Raw script', t => {
250 | const forge = createForge({
251 | change: { script: 'OP_TRUE' }
252 | })
253 |
254 | t.true(forge.changeScript instanceof nimble.Script)
255 | t.is(forge.changeScript.length, 1)
256 | })
257 |
258 | test('createForge() sets given locktime', t => {
259 | const forge = createForge({
260 | locktime: 999999
261 | })
262 |
263 | t.is(forge.locktime, 999999)
264 | })
265 |
266 | test('createForge() sets given options', t => {
267 | const forge = createForge({
268 | options: { sort: true, foo: 'bar' }
269 | })
270 |
271 | t.is(forge.options.sort, true)
272 | t.is(forge.options.foo, 'bar')
273 | t.deepEqual(forge.options.rates, { standard: 50, data: 50 })
274 | })
275 |
276 | test('forgeTx() returns a built transaction', t => {
277 | const txid = '0000000000000000000000000000000000000000000000000000000000000000'
278 | const tx = forgeTx({
279 | inputs: [
280 | P2PKH.unlock(toUTXO({ txid, vout: 0, satoshis: 10000, script: '006a' }), { privkey }),
281 | P2PK.unlock(toUTXO({ txid, vout: 0, satoshis: 10000, script: '006a' }), { privkey })
282 | ],
283 | outputs: [
284 | P2PKH.lock(10000, { address }),
285 | P2PK.lock(10000, { pubkey }),
286 | OpReturn.lock(0, { data: 'hello world' })
287 | ]
288 | })
289 |
290 | t.is(tx.inputs.length, 2)
291 | t.is(tx.outputs.length, 3)
292 | })
293 |
294 | test('forgeTx() sets change on the tx', t => {
295 | const txid = '0000000000000000000000000000000000000000000000000000000000000000'
296 | const tx = forgeTx({
297 | inputs: [
298 | P2PKH.unlock(toUTXO({ txid, vout: 0, satoshis: 10000, script: '006a' }), { privkey }),
299 | ],
300 | outputs: [
301 | P2PKH.lock(1000, { address }),
302 | ],
303 | change: { address }
304 | })
305 |
306 | t.is(tx.inputs.length, 1)
307 | t.is(tx.outputs.length, 2)
308 | })
309 |
310 | test('forgeTx() sets locktime on the tx', t => {
311 | const tx = forgeTx({
312 | locktime: 999999
313 | })
314 |
315 | t.is(tx.locktime, 999999)
316 | })
317 |
318 | test('forgeTx() uses given rates', t => {
319 | const txid = '0000000000000000000000000000000000000000000000000000000000000000'
320 | const tx = forgeTx({
321 | inputs: [
322 | P2PKH.unlock(toUTXO({ txid, vout: 0, satoshis: 10000, script: '006a' }), { privkey }),
323 | ],
324 | outputs: [
325 | OpReturn.lock(0, { data: new Array(1000).fill(0) }),
326 | ],
327 | change: { address },
328 | options: { rates: 1000 }
329 | })
330 |
331 | t.true(tx.fee > 1200)
332 | })
333 |
--------------------------------------------------------------------------------
/test/classes/shared.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import { getOpt } from '../../src/classes/shared.js'
3 |
4 | test('getOpt() gets the first found value from the list of keys', t => {
5 | const params = { foo: 1, bar: 0 }
6 | t.is(getOpt(params, ['foo', 'bar']), 1)
7 | t.is(getOpt(params, ['barx', 'bar', 'foo']), 0)
8 | })
9 |
10 | test('getOpt() returns undefined if no value found from keys', t => {
11 | const params = { foo: 1, bar: 0 }
12 | t.is(getOpt(params, ['foo1', 'foo2', 'foo3']), undefined)
13 | })
14 |
15 | test('getOpt() returns default if no value found from keys', t => {
16 | const params = { foo: 1, bar: 0 }
17 | t.is(getOpt(params, ['foo1', 'foo2', 'foo3'], 999), 999)
18 | })
19 |
--------------------------------------------------------------------------------
/test/classes/tape.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import nimble from '@runonbitcoin/nimble'
3 | import { Tape, toScript } from '../../src/index.js'
4 |
5 | const { opcodes } = nimble.constants
6 |
7 | test('Tape.push() pushes an opcode onto the tape', t => {
8 | const tape = new Tape()
9 | tape.push(opcodes.OP_RETURN)
10 | t.deepEqual(tape.cells, [{ opcode: 106 }])
11 | })
12 |
13 | test('Tape.push() pushes a buffer onto the tape', t => {
14 | const tape = new Tape()
15 | tape.push(Array.from(new Uint8Array([1,2,3,4])))
16 | t.deepEqual(tape.cells, [{ buf: [1,2,3,4] }])
17 | })
18 |
19 | test('Tape.push() pushes a string onto the tape', t => {
20 | const tape = new Tape()
21 | tape.push('hello')
22 | t.true(tape.cells[0].buf instanceof Uint8Array)
23 | })
24 |
25 | test('Tape.push() pushes an array of elements onto the tape', t => {
26 | const tape = new Tape()
27 | tape.push([opcodes.OP_RETURN, 'hello', new Uint8Array([1,2,3,4])])
28 | t.is(tape.cells.length, 3)
29 | })
30 |
31 | test('Tape.push() throws if an invalid integer', t => {
32 | const tape = new Tape()
33 | t.throws(_ => tape.push(999))
34 | })
35 |
36 | test('Tape.push() throws if an unknown type', t => {
37 | const tape = new Tape()
38 | t.throws(_ => tape.push({ foo: 'bar' }))
39 | })
40 |
41 |
42 | test('Tape.apply() applies the macro to the tape', t => {
43 | function macro(code) {
44 | this.script.push(code)
45 | }
46 | const tape = new Tape()
47 | tape.apply(macro, [opcodes.OP_RETURN])
48 |
49 | t.deepEqual(tape.cells, [{ opcode: 106 }])
50 | })
51 |
52 | test('Tape.apply() throws helpful error if arguments not an array', t => {
53 | function macro(code) {
54 | this.script.push(code)
55 | }
56 | const tape = new Tape()
57 | t.throws(_ => tape.apply(macro, opcodes.OP_RETURN), { message: /^invalid args/ })
58 | })
59 |
60 | test('Tape.each() iterates over the elements', t => {
61 | const tape = new Tape()
62 | tape.each([1,2,3], (el, i) => tape.push([el, i]))
63 | t.is(tape.cells.length, 3)
64 | t.deepEqual(tape.cells[0], { buf: [1, 0] })
65 | })
66 |
67 | test('Tape.repeats() iterates the specified number of times', t => {
68 | const tape = new Tape()
69 | tape.repeat(3, (i) => tape.push([i]))
70 | t.is(tape.cells.length, 3)
71 | t.deepEqual(tape.cells[0], { buf: [0] })
72 | })
73 |
74 | test('toScript() converts the tape to a script', t => {
75 | const tape = new Tape()
76 | tape.push(opcodes.OP_RETURN).push('hello')
77 | const script = toScript(tape)
78 |
79 | t.true(script instanceof nimble.Script)
80 | t.is(script.toHex(), '6a0568656c6c6f')
81 | })
82 |
83 | test('toScript() throws if the argument is not a tape', t => {
84 | t.throws(_ => toScript('hello'), { message: /^invalid argument/ })
85 | })
--------------------------------------------------------------------------------
/test/classes/utxo.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import nimble from '@runonbitcoin/nimble'
3 | import { toUTXO, getUTXO, forgeTx, casts} from '../../src/index.js'
4 |
5 | const { Transaction, Script } = nimble.classes
6 |
7 | test('toUTXO() accepts Mattercloud api params', t => {
8 | const params = {
9 | "address": "12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX",
10 | "txid": "5e3014372338f079f005eedc85359e4d96b8440e7dbeb8c35c4182e0c19a1a12",
11 | "vout": 0,
12 | "amount": 0.00015399,
13 | "satoshis": 15399,
14 | "value": 15399,
15 | "height": 576168,
16 | "confirmations": 34993,
17 | "scriptPubKey": "76a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac",
18 | "script": "76a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac",
19 | "outputIndex": 0
20 | }
21 |
22 | const utxo = toUTXO(params)
23 | t.is(utxo.txid, params.txid)
24 | t.is(utxo.vout, params.vout)
25 | t.is(utxo.satoshis, params.satoshis)
26 | t.true(utxo.script instanceof Script)
27 | t.true(utxo.output instanceof Transaction.Output)
28 | })
29 |
30 | test('toUTXO() accepts WOC api params', t => {
31 | const params = {
32 | "height": 578325,
33 | "tx_pos": 0,
34 | "tx_hash": "62824e3af3d01113e9bce8b73576b833990d231357bd718385958c21d50bbddd",
35 | "value": 1250020815
36 | }
37 |
38 | const utxo = toUTXO(params)
39 | t.is(utxo.txid, params.tx_hash)
40 | t.is(utxo.vout, params.tx_pos)
41 | t.is(utxo.satoshis, params.value)
42 | })
43 |
44 | test('getUTXO() gets UTXO from the given tx and vout', t => {
45 | const tx = forgeTx({
46 | outputs: [casts.Raw.lock(1000, { script: new Script() })]
47 | })
48 |
49 | const utxo = getUTXO(tx, 0)
50 | t.is(utxo.txid, tx.hash)
51 | t.is(utxo.vout, 0)
52 | t.is(utxo.satoshis, 1000)
53 | t.true(utxo.script instanceof Script)
54 | t.true(utxo.output instanceof Transaction.Output)
55 | })
56 |
--------------------------------------------------------------------------------
/test/extra/r-puzzle.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import { generateK, calculateR } from '../../src/extra/r-puzzle.js'
3 |
4 | test('generateK() returns random K value', t => {
5 | const k = generateK()
6 | t.true(k instanceof Uint8Array)
7 | t.is(k.length, 32)
8 | })
9 |
10 | test('calculateR() returns R from K', t => {
11 | const k = generateK()
12 | const r = calculateR(k)
13 | t.true(r instanceof Uint8Array)
14 | t.true([32,33].includes(r.length))
15 | })
16 |
--------------------------------------------------------------------------------
/test/helpers/asm.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import { asm } from '../../src/helpers/index.js'
3 |
4 | const str = 'OP_DUP OP_HASH160 5ae866af9de106847de6111e5f1faa168b2be689 OP_EQUALVERIFY OP_CHECKSIG'
5 |
6 | test('asm() converts asm string to script chunks', t => {
7 | const chunks = asm(str)
8 | t.is(chunks.length, 5)
9 | t.is(chunks[0].opcode, 118)
10 | t.is(chunks[1].opcode, 169)
11 | t.is(chunks[3].opcode, 136)
12 | t.is(chunks[4].opcode, 172)
13 | })
14 |
15 | test('asm() throws with invalid asm string', t => {
16 | t.throws(_ => asm('OP_RETURN xyz OP_0'))
17 | })
18 |
--------------------------------------------------------------------------------
/test/helpers/num.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import { num } from '../../src/helpers/index.js'
3 |
4 | test('num() returns integer for small ints', t => {
5 | t.is(num(0), 0)
6 | t.is(num(1), 81)
7 | t.is(num(10), 90)
8 | t.is(num(16), 96)
9 | })
10 |
11 | test('num() returns byte vector for larger ints ints', t => {
12 | t.deepEqual(num(17), [17])
13 | t.deepEqual(num(3200), [128, 12])
14 | })
15 |
--------------------------------------------------------------------------------
/test/macros/binary.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import nimble from '@runonbitcoin/nimble'
3 | import { Tape, toScript } from '../../src/classes/tape.js'
4 | import { decodeUint, reverse, slice, trim } from '../../src/macros/index.js'
5 |
6 | const { evalScript, generateRandomData } = nimble.functions
7 |
8 | test('decodeUint() casts the top stack element to a script number', t => {
9 | function uintBuf(len, cb) {
10 | const buf = new ArrayBuffer(len)
11 | const view = new DataView(buf)
12 | cb(view)
13 | return new Uint8Array(view.buffer)
14 | }
15 |
16 | const bufs = [
17 | uintBuf(1, v => v.setUint8(0, 24, true)),
18 | uintBuf(4, v => v.setUint32(0, 24, true)),
19 | uintBuf(4, v => v.setUint32(0, 4000000000, true)),
20 | ]
21 |
22 | const b = new Tape()
23 | b.each(bufs, buf => {
24 | b.push(buf).apply(decodeUint)
25 | })
26 |
27 | const script = toScript(b)
28 | const { stack } = evalScript([], script)
29 |
30 | const expected = [[24], [24], [0, 40, 107, 238, 0]]
31 | t.deepEqual(stack, expected)
32 | })
33 |
34 | test('reverse() reverses the data on top of the stack', t => {
35 | const bufs = [
36 | [1,2,3,4,5],
37 | [1,2,3,4,5,6,7,8],
38 | [1,2,3,4,5,6,7,8,9,10,11,12],
39 | [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16],
40 | [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25],
41 | [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32],
42 | [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34],
43 | Array.from(generateRandomData(560))
44 | ]
45 | t.plan(bufs.length)
46 |
47 | for (let buf of bufs) {
48 | const b = new Tape()
49 | b.push(buf)
50 | b.apply(reverse, [buf.length])
51 |
52 | const script = toScript(b)
53 | const { stack } = evalScript([], script)
54 |
55 | t.deepEqual(stack[0], buf.reverse())
56 | }
57 | })
58 |
59 | test('slice() slices bytes from the top of the stack', t => {
60 | t.plan(5)
61 |
62 | // When start has positive index
63 | for (let args of [[0, 2], [4, 4], [13, 2]]) {
64 | const buf = new Uint8Array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16])
65 | const b = new Tape()
66 | b.push(buf)
67 | b.apply(slice, args)
68 |
69 | const script = toScript(b)
70 | const { stack } = evalScript([], script)
71 |
72 | const expected = buf.slice(args[0], args[0] + args[1])
73 | t.deepEqual(stack[0], expected)
74 | }
75 |
76 | // When start has negative index
77 | for (let args of [[-4, 4], [-13, 2]]) {
78 | const buf = new Uint8Array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16])
79 | const b = new Tape()
80 | b.push(buf)
81 | b.apply(slice, args)
82 |
83 | const script = toScript(b)
84 | const { stack } = evalScript([], script)
85 |
86 | const expected = buf.slice(buf.length + args[0], buf.length + args[0] + args[1])
87 | t.deepEqual(stack[0], expected)
88 | }
89 | })
90 |
91 | test('trim() trims leading bytes from the top of the stack', t => {
92 | t.plan(4)
93 |
94 | for (let arg of [2, 4, 8, 13]) {
95 | const buf = new Uint8Array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16])
96 | const b = new Tape()
97 | b.push(buf)
98 | b.apply(trim, [arg])
99 |
100 | const script = toScript(b)
101 | const { stack } = evalScript([], script)
102 |
103 | const expected = buf.slice(arg)
104 | t.deepEqual(stack[0], expected)
105 | }
106 | })
107 |
108 | test('trim() trims trailing bytes from the top of the stack', t => {
109 | t.plan(4)
110 |
111 | for (let arg of [-2, -4, -8, -13]) {
112 | const buf = new Uint8Array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16])
113 | const b = new Tape()
114 | b.push(buf)
115 | b.apply(trim, [arg])
116 |
117 | const script = toScript(b)
118 | const { stack } = evalScript([], script)
119 |
120 | const expected = buf.slice(0, buf.length+arg)
121 | t.deepEqual(stack[0], expected)
122 | }
123 | })
--------------------------------------------------------------------------------
/test/macros/push-tx.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import nimble from '@runonbitcoin/nimble'
3 | import { casts, forgeTx, Cast, getUTXO } from '../../src/index.js'
4 | import { Tape, toScript } from '../../src/classes/tape.js'
5 | import { num } from '../../src/helpers/index.js'
6 | import {
7 | getVersion,
8 | getPrevoutsHash,
9 | getSequenceHash,
10 | getOutpoint,
11 | getScript,
12 | getSatoshis,
13 | getSequence,
14 | getOutputsHash,
15 | getLocktime,
16 | getSighashType,
17 | pushTx,
18 | checkTx,
19 | checkTxVerify,
20 | checkTxOpt,
21 | } from '../../src/macros/index.js'
22 |
23 | const { Script } = nimble.classes
24 | const { decodeHex, evalScript, preimage } = nimble.functions
25 | const { OP_DROP } = nimble.constants.opcodes
26 |
27 | const prevTx = forgeTx({
28 | outputs: [
29 | casts.P2PKH.lock(50000, { address: '15KgnG69mTbtkx73vNDNUdrWuDhnmfCxsf' })
30 | ]
31 | })
32 |
33 | const utxo = getUTXO(prevTx, 0)
34 |
35 | const testTx = forgeTx({
36 | inputs: [
37 | casts.Raw.unlock(utxo, { script: new Script() })
38 | ]
39 | })
40 |
41 | const prevOut = prevTx.outputs[0]
42 | const preimg = preimage(testTx, 0, prevOut.script, prevOut.satoshis, 0x41)
43 |
44 |
45 | test('getVersion() puts tx version on top of stack', t => {
46 | const b = new Tape()
47 | b.push(preimg).apply(getVersion)
48 | const script = toScript(b)
49 | const { stack } = evalScript([], script)
50 |
51 | t.deepEqual(stack[stack.length-1], [1])
52 | })
53 |
54 | test('getPrevoutsHash() puts prev outpoints hash on top of stack', t => {
55 | const b = new Tape()
56 | b.push(preimg).apply(getPrevoutsHash)
57 | const script = toScript(b)
58 | const { stack } = evalScript([], script)
59 |
60 | const expected = Array.from(testTx._hashPrevouts)
61 | t.deepEqual(stack[stack.length-1], expected)
62 | })
63 |
64 | test('getSequenceHash() puts txin sequence hash on top of stack', t => {
65 | const b = new Tape()
66 | b.push(preimg).apply(getSequenceHash)
67 | const script = toScript(b)
68 | const { stack } = evalScript([], script)
69 |
70 | const expected = Array.from(testTx._hashSequence)
71 | t.deepEqual(stack[stack.length-1], expected)
72 | })
73 |
74 | test('getOutpoint() puts txin outpoint on top of stack', t => {
75 | const b = new Tape()
76 | b.push(preimg).apply(getOutpoint)
77 | const script = toScript(b)
78 | const { stack } = evalScript([], script)
79 |
80 | const expected = Array.from(decodeHex(prevTx.hash).reverse()).concat([0,0,0,0])
81 | t.deepEqual(stack[stack.length-1], expected)
82 | })
83 |
84 | test('getScript() puts lock script on top of stack', t => {
85 | const b = new Tape()
86 | b.push(preimg).apply(getScript)
87 | const script = toScript(b)
88 | const { stack } = evalScript([], script)
89 |
90 | t.deepEqual(stack[stack.length-1], Array.from(prevOut.script.buffer))
91 | })
92 |
93 | test('getSatoshis() puts lock satoshis on top of stack', t => {
94 | const b = new Tape()
95 | b.push(preimg).apply(getSatoshis)
96 | const script = toScript(b)
97 | const { stack } = evalScript([], script)
98 |
99 | t.deepEqual(stack[stack.length-1], num(50000))
100 | })
101 |
102 | test('getSequence() puts txin sequence on top of stack', t => {
103 | const b = new Tape()
104 | b.push(preimg).apply(getSequence)
105 | const script = toScript(b)
106 | const { stack } = evalScript([], script)
107 |
108 | t.deepEqual(stack[stack.length-1], num(0xFFFFFFFF))
109 | })
110 |
111 | test('getOutputsHash() puts tx outputs hash on top of stack', t => {
112 | const b = new Tape()
113 | b.push(preimg).apply(getOutputsHash)
114 | const script = toScript(b)
115 | const { stack } = evalScript([], script)
116 |
117 | const expected = Array.from(testTx._hashOutputsAll)
118 | t.deepEqual(stack[stack.length-1], expected)
119 | })
120 |
121 | test('getLocktime() puts tx locktime on top of stack', t => {
122 | const b = new Tape()
123 | b.push(preimg).apply(getLocktime).push([1])
124 | const script = toScript(b)
125 | const { stack } = evalScript([], script)
126 |
127 | t.deepEqual(stack[stack.length-2], [])
128 | })
129 |
130 | test('getSighashType() puts tx sighash type on top of stack', t => {
131 | const b = new Tape()
132 | b.push(preimg).apply(getSighashType)
133 | const script = toScript(b)
134 | const { stack } = evalScript([], script)
135 |
136 | t.deepEqual(stack[stack.length-1], [0x41])
137 | })
138 |
139 | test('pushTx() pushes the tx preimage onto the stack', t => {
140 | const b = new Tape()
141 | b.cast.ctx = { tx: testTx, vin: 0 }
142 | b.cast.utxo = utxo
143 | b.apply(pushTx)
144 | const script = toScript(b)
145 | const { stack } = evalScript(script, [])
146 |
147 | t.deepEqual(stack[0], preimg)
148 | })
149 |
150 | test('pushTx() pushes zero bytes placeholder onto the stack without context', t => {
151 | const b = new Tape()
152 | b.apply(pushTx).push([1])
153 | const script = toScript(b)
154 | const { stack } = evalScript(script, [])
155 |
156 | t.deepEqual(stack[0], new Uint8Array(181).fill(0))
157 | })
158 |
159 | class TestCast extends Cast {
160 | lockingScript({ extraBytes, optimized, verify }) {
161 | if (extraBytes) {
162 | this.script.push([0]).push(OP_DROP)
163 | }
164 | if (optimized) {
165 | this.script.apply(checkTxOpt)
166 | } else if (verify) {
167 | this.script.apply(checkTxVerify).push([1,2,3])
168 | } else {
169 | this.script.apply(checkTx)
170 | }
171 | }
172 |
173 | unlockingScript() {
174 | this.script.apply(pushTx)
175 | }
176 | }
177 |
178 | test('TestCast simulates full check tx', t => {
179 | const vm = TestCast.simulate()
180 | t.true(vm.success)
181 | })
182 |
183 | test('TestCast simulates full check tx verify', t => {
184 | const vm = TestCast.simulate({ verify: true })
185 | t.true(vm.success)
186 | })
187 |
188 | test('TestCast simulates optimal check tx verify', t => {
189 | const vm = TestCast.simulate({ optimized: true })
190 | t.true(vm.success)
191 | })
192 |
193 | test('TestCast optimal check has 50% chance of not working', t => {
194 | const vm = TestCast.simulate({ optimized: true, extraBytes: true })
195 | t.false(vm.success)
196 | t.truthy(vm.error)
197 | })
198 |
--------------------------------------------------------------------------------
/test/macros/varint.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import nimble from '@runonbitcoin/nimble'
3 | import { Tape, toScript } from '../../src/classes/tape.js'
4 | import { num } from '../../src/helpers/index.js'
5 | import { getVarint, readVarint, trimVarint } from '../../src/macros/index.js'
6 |
7 | const { BufferWriter } = nimble.classes
8 | const { evalScript, writeVarint } = nimble.functions
9 |
10 | test('getVarint() gets the varint from the top stack element and puts on top', t => {
11 | for (let bytes of [32, 320, 320000]) {
12 | const data = new Uint8Array(bytes).fill(1)
13 | const buf = new BufferWriter()
14 | writeVarint(buf, data.length)
15 | buf.write(data)
16 | const b = new Tape()
17 | b.push(buf).apply(getVarint)
18 |
19 | const script = toScript(b)
20 | const { stack } = evalScript([], script)
21 |
22 | const expected = [buf.toBuffer(), num(bytes)]
23 | t.deepEqual(stack, expected)
24 | }
25 | })
26 |
27 | test('readVarint() reads the varint from the top stack item and puts the encoded data on top', t => {
28 | for (let bytes of [32, 320, 320000]) {
29 | const data = new Uint8Array(bytes).fill(1)
30 | const buf = new BufferWriter()
31 | writeVarint(buf, data.length)
32 | buf.write(data)
33 | buf.write([1,2,3,4])
34 | const b = new Tape()
35 | b.push(buf).apply(readVarint)
36 |
37 | const script = toScript(b)
38 | const { stack } = evalScript([], script)
39 |
40 | const expected = [new Uint8Array([1, 2, 3, 4]), data]
41 | t.deepEqual(stack, expected)
42 | }
43 | })
44 |
45 | test('trimVarint() trims the varint from the leading bytes of the top stack item', t => {
46 | for (let bytes of [32, 320, 320000]) {
47 | const data = new Uint8Array(bytes).fill(1)
48 | const buf = new BufferWriter()
49 | writeVarint(buf, data.length)
50 | buf.write(data)
51 | const b = new Tape()
52 | b.push(buf).apply(trimVarint)
53 |
54 | const script = toScript(b)
55 | const { stack } = evalScript([], script)
56 |
57 | const expected = [data]
58 | t.deepEqual(stack, expected)
59 | }
60 | })
61 |
--------------------------------------------------------------------------------
/test/vectors/bip69.json:
--------------------------------------------------------------------------------
1 | {
2 | "inputs": [
3 | {
4 | "description": "Ordered by txId, descending (reverse-byte-order ascending)",
5 | "inputs": [
6 | {
7 | "txId": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
8 | "vout": 0
9 | },
10 | {
11 | "txId": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
12 | "vout": 0
13 | },
14 | {
15 | "txId": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
16 | "vout": 0
17 | },
18 | {
19 | "txId": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbff",
20 | "vout": 0
21 | },
22 | {
23 | "txId": "ffbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
24 | "vout": 0
25 | }
26 | ],
27 | "expected": [0, 2, 3, 1, 4]
28 | },
29 | {
30 | "description": "Ordered by vout, ascending",
31 | "inputs": [
32 | {
33 | "txId": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
34 | "vout": 1
35 | },
36 | {
37 | "txId": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
38 | "vout": 2
39 | },
40 | {
41 | "txId": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
42 | "vout": 0
43 | }
44 | ],
45 | "expected": [2, 0, 1]
46 | },
47 | {
48 | "description": "Ordered by txId, then vout",
49 | "inputs": [
50 | {
51 | "txId": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
52 | "vout": 99
53 | },
54 | {
55 | "txId": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
56 | "vout": 99
57 | },
58 | {
59 | "txId": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
60 | "vout": 0
61 | },
62 | {
63 | "txId": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
64 | "vout": 0
65 | }
66 | ],
67 | "expected": [0, 3, 1, 2]
68 | },
69 | {
70 | "description": "BIP69 test vector 1",
71 | "inputs": [
72 | { "txId": "0e53ec5dfb2cb8a71fec32dc9a634a35b7e24799295ddd5278217822e0b31f57", "vout": 0 },
73 | { "txId": "26aa6e6d8b9e49bb0630aac301db6757c02e3619feb4ee0eea81eb1672947024", "vout": 1 },
74 | { "txId": "28e0fdd185542f2c6ea19030b0796051e7772b6026dd5ddccd7a2f93b73e6fc2", "vout": 0 },
75 | { "txId": "381de9b9ae1a94d9c17f6a08ef9d341a5ce29e2e60c36a52d333ff6203e58d5d", "vout": 1 },
76 | { "txId": "3b8b2f8efceb60ba78ca8bba206a137f14cb5ea4035e761ee204302d46b98de2", "vout": 0 },
77 | { "txId": "402b2c02411720bf409eff60d05adad684f135838962823f3614cc657dd7bc0a", "vout": 1 },
78 | { "txId": "54ffff182965ed0957dba1239c27164ace5a73c9b62a660c74b7b7f15ff61e7a", "vout": 1 },
79 | { "txId": "643e5f4e66373a57251fb173151e838ccd27d279aca882997e005016bb53d5aa", "vout": 0 },
80 | { "txId": "6c1d56f31b2de4bfc6aaea28396b333102b1f600da9c6d6149e96ca43f1102b1", "vout": 1 },
81 | { "txId": "7a1de137cbafb5c70405455c49c5104ca3057a1f1243e6563bb9245c9c88c191", "vout": 0 },
82 | { "txId": "7d037ceb2ee0dc03e82f17be7935d238b35d1deabf953a892a4507bfbeeb3ba4", "vout": 1 },
83 | { "txId": "a5e899dddb28776ea9ddac0a502316d53a4a3fca607c72f66c470e0412e34086", "vout": 0 },
84 | { "txId": "b4112b8f900a7ca0c8b0e7c4dfad35c6be5f6be46b3458974988e1cdb2fa61b8", "vout": 0 },
85 | { "txId": "bafd65e3c7f3f9fdfdc1ddb026131b278c3be1af90a4a6ffa78c4658f9ec0c85", "vout": 0 },
86 | { "txId": "de0411a1e97484a2804ff1dbde260ac19de841bebad1880c782941aca883b4e9", "vout": 1 },
87 | { "txId": "f0a130a84912d03c1d284974f563c5949ac13f8342b8112edff52971599e6a45", "vout": 0 },
88 | { "txId": "f320832a9d2e2452af63154bc687493484a0e7745ebd3aaf9ca19eb80834ad60", "vout": 0 }
89 | ],
90 | "expected": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
91 | },
92 | {
93 | "description": "BIP69 test vector 2",
94 | "inputs": [
95 | { "txId": "35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055", "vout": 0 },
96 | { "txId": "35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055", "vout": 1 }
97 | ],
98 | "expected": [0, 1]
99 | }
100 | ],
101 | "outputs": [
102 | {
103 | "description": "Ordered by Amount, ascending",
104 | "outputs": [
105 | {
106 | "script": "0400000000",
107 | "value": 3000
108 | },
109 | {
110 | "script": "0400000000",
111 | "value": 2000
112 | },
113 | {
114 | "script": "0400000000",
115 | "value": 1000
116 | }
117 | ],
118 | "expected": [2, 1, 0]
119 | },
120 | {
121 | "description": "Ordered by Script, ascending",
122 | "outputs": [
123 | {
124 | "script": "0400000000",
125 | "value": 1000
126 | },
127 | {
128 | "script": "0422222222",
129 | "value": 1000
130 | },
131 | {
132 | "script": "0411111111",
133 | "value": 1000
134 | }
135 | ],
136 | "expected": [0, 2, 1]
137 | },
138 | {
139 | "description": "Ordered by Amount, then Script",
140 | "outputs": [
141 | {
142 | "script": "0411111111",
143 | "value": 1000
144 | },
145 | {
146 | "script": "0411111111",
147 | "value": 2000
148 | },
149 | {
150 | "script": "0400000000",
151 | "value": 3000
152 | },
153 | {
154 | "script": "0400000000",
155 | "value": 2000
156 | }
157 | ],
158 | "expected": [0, 3, 1, 2]
159 | },
160 | {
161 | "description": "BIP69 test vector 1",
162 | "outputs": [
163 | {
164 | "script": "76a9144a5fba237213a062f6f57978f796390bdcf8d01588ac",
165 | "value": 400057456
166 | },
167 | {
168 | "script": "76a9145be32612930b8323add2212a4ec03c1562084f8488ac",
169 | "value": 40000000000
170 | }
171 | ],
172 | "expected": [0, 1]
173 | },
174 | {
175 | "description": "BIP69 test vector 2",
176 | "outputs": [
177 | {
178 | "script": "41046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac",
179 | "value": 100000000
180 | },
181 | {
182 | "script": "41044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac",
183 | "value": 2400000000
184 | }
185 | ],
186 | "expected": [0, 1]
187 | }
188 | ]
189 | }
190 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # This file is generated by running "yarn install" inside your project.
2 | # Manual changes might be lost - proceed with caution!
3 |
4 | __metadata:
5 | version: 6
6 | cacheKey: 8
7 |
8 | "@gar/promisify@npm:^1.1.3":
9 | version: 1.1.3
10 | resolution: "@gar/promisify@npm:1.1.3"
11 | checksum: 4059f790e2d07bf3c3ff3e0fec0daa8144fe35c1f6e0111c9921bd32106adaa97a4ab096ad7dab1e28ee6a9060083c4d1a4ada42a7f5f3f7a96b8812e2b757c1
12 | languageName: node
13 | linkType: hard
14 |
15 | "@nodelib/fs.scandir@npm:2.1.5":
16 | version: 2.1.5
17 | resolution: "@nodelib/fs.scandir@npm:2.1.5"
18 | dependencies:
19 | "@nodelib/fs.stat": 2.0.5
20 | run-parallel: ^1.1.9
21 | checksum: a970d595bd23c66c880e0ef1817791432dbb7acbb8d44b7e7d0e7a22f4521260d4a83f7f9fd61d44fda4610105577f8f58a60718105fb38352baed612fd79e59
22 | languageName: node
23 | linkType: hard
24 |
25 | "@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2":
26 | version: 2.0.5
27 | resolution: "@nodelib/fs.stat@npm:2.0.5"
28 | checksum: 012480b5ca9d97bff9261571dbbec7bbc6033f69cc92908bc1ecfad0792361a5a1994bc48674b9ef76419d056a03efadfce5a6cf6dbc0a36559571a7a483f6f0
29 | languageName: node
30 | linkType: hard
31 |
32 | "@nodelib/fs.walk@npm:^1.2.3":
33 | version: 1.2.8
34 | resolution: "@nodelib/fs.walk@npm:1.2.8"
35 | dependencies:
36 | "@nodelib/fs.scandir": 2.1.5
37 | fastq: ^1.6.0
38 | checksum: 190c643f156d8f8f277bf2a6078af1ffde1fd43f498f187c2db24d35b4b4b5785c02c7dc52e356497b9a1b65b13edc996de08de0b961c32844364da02986dc53
39 | languageName: node
40 | linkType: hard
41 |
42 | "@npmcli/fs@npm:^2.1.0":
43 | version: 2.1.0
44 | resolution: "@npmcli/fs@npm:2.1.0"
45 | dependencies:
46 | "@gar/promisify": ^1.1.3
47 | semver: ^7.3.5
48 | checksum: 6ec6d678af6da49f9dac50cd882d7f661934dd278972ffbaacde40d9eaa2871292d634000a0cca9510f6fc29855fbd4af433e1adbff90a524ec3eaf140f1219b
49 | languageName: node
50 | linkType: hard
51 |
52 | "@npmcli/move-file@npm:^2.0.0":
53 | version: 2.0.0
54 | resolution: "@npmcli/move-file@npm:2.0.0"
55 | dependencies:
56 | mkdirp: ^1.0.4
57 | rimraf: ^3.0.2
58 | checksum: 1388777b507b0c592d53f41b9d182e1a8de7763bc625fc07999b8edbc22325f074e5b3ec90af79c89d6987fdb2325bc66d59f483258543c14a43661621f841b0
59 | languageName: node
60 | linkType: hard
61 |
62 | "@runonbitcoin/nimble@npm:^1.0.13":
63 | version: 1.0.13
64 | resolution: "@runonbitcoin/nimble@npm:1.0.13"
65 | checksum: b4e7de91dcbb8355cd6444431710750e4f421dea28669c9cfd5accd1c368610238c3c591ce7ca8b6ffec38d552efd9ccd2fc6b1804b00587f6fe753bdf231481
66 | languageName: node
67 | linkType: hard
68 |
69 | "@tootallnate/once@npm:2":
70 | version: 2.0.0
71 | resolution: "@tootallnate/once@npm:2.0.0"
72 | checksum: ad87447820dd3f24825d2d947ebc03072b20a42bfc96cbafec16bff8bbda6c1a81fcb0be56d5b21968560c5359a0af4038a68ba150c3e1694fe4c109a063bed8
73 | languageName: node
74 | linkType: hard
75 |
76 | "abbrev@npm:1":
77 | version: 1.1.1
78 | resolution: "abbrev@npm:1.1.1"
79 | checksum: a4a97ec07d7ea112c517036882b2ac22f3109b7b19077dc656316d07d308438aac28e4d9746dc4d84bf6b1e75b4a7b0a5f3cb30592419f128ca9a8cee3bcfa17
80 | languageName: node
81 | linkType: hard
82 |
83 | "acorn-walk@npm:^8.2.0":
84 | version: 8.2.0
85 | resolution: "acorn-walk@npm:8.2.0"
86 | checksum: 1715e76c01dd7b2d4ca472f9c58968516a4899378a63ad5b6c2d668bba8da21a71976c14ec5f5b75f887b6317c4ae0b897ab141c831d741dc76024d8745f1ad1
87 | languageName: node
88 | linkType: hard
89 |
90 | "acorn@npm:^8.7.0":
91 | version: 8.7.1
92 | resolution: "acorn@npm:8.7.1"
93 | bin:
94 | acorn: bin/acorn
95 | checksum: aca0aabf98826717920ac2583fdcad0a6fbe4e583fdb6e843af2594e907455aeafe30b1e14f1757cd83ce1776773cf8296ffc3a4acf13f0bd3dfebcf1db6ae80
96 | languageName: node
97 | linkType: hard
98 |
99 | "agent-base@npm:6, agent-base@npm:^6.0.2":
100 | version: 6.0.2
101 | resolution: "agent-base@npm:6.0.2"
102 | dependencies:
103 | debug: 4
104 | checksum: f52b6872cc96fd5f622071b71ef200e01c7c4c454ee68bc9accca90c98cfb39f2810e3e9aa330435835eedc8c23f4f8a15267f67c6e245d2b33757575bdac49d
105 | languageName: node
106 | linkType: hard
107 |
108 | "agentkeepalive@npm:^4.2.1":
109 | version: 4.2.1
110 | resolution: "agentkeepalive@npm:4.2.1"
111 | dependencies:
112 | debug: ^4.1.0
113 | depd: ^1.1.2
114 | humanize-ms: ^1.2.1
115 | checksum: 39cb49ed8cf217fd6da058a92828a0a84e0b74c35550f82ee0a10e1ee403c4b78ade7948be2279b188b7a7303f5d396ea2738b134731e464bf28de00a4f72a18
116 | languageName: node
117 | linkType: hard
118 |
119 | "aggregate-error@npm:^3.0.0":
120 | version: 3.1.0
121 | resolution: "aggregate-error@npm:3.1.0"
122 | dependencies:
123 | clean-stack: ^2.0.0
124 | indent-string: ^4.0.0
125 | checksum: 1101a33f21baa27a2fa8e04b698271e64616b886795fd43c31068c07533c7b3facfcaf4e9e0cab3624bd88f729a592f1c901a1a229c9e490eafce411a8644b79
126 | languageName: node
127 | linkType: hard
128 |
129 | "aggregate-error@npm:^4.0.0":
130 | version: 4.0.0
131 | resolution: "aggregate-error@npm:4.0.0"
132 | dependencies:
133 | clean-stack: ^4.0.0
134 | indent-string: ^5.0.0
135 | checksum: 586397769e25fc5c2da5995c736f11ba83adf0bbc5f72c7101ea38e795458fd7b497f672318119218b4d3b1f8b8d3001417cebe9de55b5467af5cbcbff4befa3
136 | languageName: node
137 | linkType: hard
138 |
139 | "ansi-regex@npm:^5.0.1":
140 | version: 5.0.1
141 | resolution: "ansi-regex@npm:5.0.1"
142 | checksum: 2aa4bb54caf2d622f1afdad09441695af2a83aa3fe8b8afa581d205e57ed4261c183c4d3877cee25794443fde5876417d859c108078ab788d6af7e4fe52eb66b
143 | languageName: node
144 | linkType: hard
145 |
146 | "ansi-regex@npm:^6.0.1":
147 | version: 6.0.1
148 | resolution: "ansi-regex@npm:6.0.1"
149 | checksum: 1ff8b7667cded1de4fa2c9ae283e979fc87036864317da86a2e546725f96406746411d0d85e87a2d12fa5abd715d90006de7fa4fa0477c92321ad3b4c7d4e169
150 | languageName: node
151 | linkType: hard
152 |
153 | "ansi-styles@npm:^4.0.0":
154 | version: 4.3.0
155 | resolution: "ansi-styles@npm:4.3.0"
156 | dependencies:
157 | color-convert: ^2.0.1
158 | checksum: 513b44c3b2105dd14cc42a19271e80f386466c4be574bccf60b627432f9198571ebf4ab1e4c3ba17347658f4ee1711c163d574248c0c1cdc2d5917a0ad582ec4
159 | languageName: node
160 | linkType: hard
161 |
162 | "ansi-styles@npm:^6.0.0, ansi-styles@npm:^6.1.0":
163 | version: 6.1.0
164 | resolution: "ansi-styles@npm:6.1.0"
165 | checksum: 7a7f8528c07a9d20c3a92bccd2b6bc3bb4d26e5cb775c02826921477377bd495d615d61f710d56216344b6238d1d11ef2b0348e146c5b128715578bfb3217229
166 | languageName: node
167 | linkType: hard
168 |
169 | "anymatch@npm:~3.1.2":
170 | version: 3.1.2
171 | resolution: "anymatch@npm:3.1.2"
172 | dependencies:
173 | normalize-path: ^3.0.0
174 | picomatch: ^2.0.4
175 | checksum: 985163db2292fac9e5a1e072bf99f1b5baccf196e4de25a0b0b81865ebddeb3b3eb4480734ef0a2ac8c002845396b91aa89121f5b84f93981a4658164a9ec6e9
176 | languageName: node
177 | linkType: hard
178 |
179 | "aproba@npm:^1.0.3 || ^2.0.0":
180 | version: 2.0.0
181 | resolution: "aproba@npm:2.0.0"
182 | checksum: 5615cadcfb45289eea63f8afd064ab656006361020e1735112e346593856f87435e02d8dcc7ff0d11928bc7d425f27bc7c2a84f6c0b35ab0ff659c814c138a24
183 | languageName: node
184 | linkType: hard
185 |
186 | "are-we-there-yet@npm:^3.0.0":
187 | version: 3.0.0
188 | resolution: "are-we-there-yet@npm:3.0.0"
189 | dependencies:
190 | delegates: ^1.0.0
191 | readable-stream: ^3.6.0
192 | checksum: 348edfdd931b0b50868b55402c01c3f64df1d4c229ab6f063539a5025fd6c5f5bb8a0cab409bbed8d75d34762d22aa91b7c20b4204eb8177063158d9ba792981
193 | languageName: node
194 | linkType: hard
195 |
196 | "argparse@npm:^1.0.7":
197 | version: 1.0.10
198 | resolution: "argparse@npm:1.0.10"
199 | dependencies:
200 | sprintf-js: ~1.0.2
201 | checksum: 7ca6e45583a28de7258e39e13d81e925cfa25d7d4aacbf806a382d3c02fcb13403a07fb8aeef949f10a7cfe4a62da0e2e807b348a5980554cc28ee573ef95945
202 | languageName: node
203 | linkType: hard
204 |
205 | "array-find-index@npm:^1.0.1":
206 | version: 1.0.2
207 | resolution: "array-find-index@npm:1.0.2"
208 | checksum: aac128bf369e1ac6c06ff0bb330788371c0e256f71279fb92d745e26fb4b9db8920e485b4ec25e841c93146bf71a34dcdbcefa115e7e0f96927a214d237b7081
209 | languageName: node
210 | linkType: hard
211 |
212 | "array-union@npm:^2.1.0":
213 | version: 2.1.0
214 | resolution: "array-union@npm:2.1.0"
215 | checksum: 5bee12395cba82da674931df6d0fea23c4aa4660cb3b338ced9f828782a65caa232573e6bf3968f23e0c5eb301764a382cef2f128b170a9dc59de0e36c39f98d
216 | languageName: node
217 | linkType: hard
218 |
219 | "arrgv@npm:^1.0.2":
220 | version: 1.0.2
221 | resolution: "arrgv@npm:1.0.2"
222 | checksum: 470bbb406ea3b34810dd8b03c0b33282617a42d9fce0ab45d58596efefd042fc548eda49161fa8e3f607cbe9df90e7a67003a09043ab9081eff70f97c63dd0e2
223 | languageName: node
224 | linkType: hard
225 |
226 | "arrify@npm:^3.0.0":
227 | version: 3.0.0
228 | resolution: "arrify@npm:3.0.0"
229 | checksum: d6c6f3dad9571234f320e130d57fddb2cc283c87f2ac7df6c7005dffc5161b7bb9376f4be655ed257050330336e84afc4f3020d77696ad231ff580a94ae5aba6
230 | languageName: node
231 | linkType: hard
232 |
233 | "ava@npm:^4.2.0":
234 | version: 4.2.0
235 | resolution: "ava@npm:4.2.0"
236 | dependencies:
237 | acorn: ^8.7.0
238 | acorn-walk: ^8.2.0
239 | ansi-styles: ^6.1.0
240 | arrgv: ^1.0.2
241 | arrify: ^3.0.0
242 | callsites: ^4.0.0
243 | cbor: ^8.1.0
244 | chalk: ^5.0.0
245 | chokidar: ^3.5.3
246 | chunkd: ^2.0.1
247 | ci-info: ^3.3.0
248 | ci-parallel-vars: ^1.0.1
249 | clean-yaml-object: ^0.1.0
250 | cli-truncate: ^3.1.0
251 | code-excerpt: ^4.0.0
252 | common-path-prefix: ^3.0.0
253 | concordance: ^5.0.4
254 | currently-unhandled: ^0.4.1
255 | debug: ^4.3.3
256 | del: ^6.0.0
257 | emittery: ^0.10.1
258 | figures: ^4.0.0
259 | globby: ^13.1.1
260 | ignore-by-default: ^2.0.0
261 | indent-string: ^5.0.0
262 | is-error: ^2.2.2
263 | is-plain-object: ^5.0.0
264 | is-promise: ^4.0.0
265 | matcher: ^5.0.0
266 | mem: ^9.0.2
267 | ms: ^2.1.3
268 | p-event: ^5.0.1
269 | p-map: ^5.3.0
270 | picomatch: ^2.3.1
271 | pkg-conf: ^4.0.0
272 | plur: ^5.1.0
273 | pretty-ms: ^7.0.1
274 | resolve-cwd: ^3.0.0
275 | slash: ^3.0.0
276 | stack-utils: ^2.0.5
277 | strip-ansi: ^7.0.1
278 | supertap: ^3.0.1
279 | temp-dir: ^2.0.0
280 | write-file-atomic: ^4.0.1
281 | yargs: ^17.3.1
282 | peerDependencies:
283 | "@ava/typescript": "*"
284 | peerDependenciesMeta:
285 | "@ava/typescript":
286 | optional: true
287 | bin:
288 | ava: entrypoints/cli.mjs
289 | checksum: dc43f8b775f93f6fe2332de83e0051cdfef63014921fe79a57fc3c2b586d6443981091f7c193131a25b378655449fce9f5080460360a09d258f1697e3bfbb04d
290 | languageName: node
291 | linkType: hard
292 |
293 | "balanced-match@npm:^1.0.0":
294 | version: 1.0.2
295 | resolution: "balanced-match@npm:1.0.2"
296 | checksum: 9706c088a283058a8a99e0bf91b0a2f75497f185980d9ffa8b304de1d9e58ebda7c72c07ebf01dadedaac5b2907b2c6f566f660d62bd336c3468e960403b9d65
297 | languageName: node
298 | linkType: hard
299 |
300 | "binary-extensions@npm:^2.0.0":
301 | version: 2.2.0
302 | resolution: "binary-extensions@npm:2.2.0"
303 | checksum: ccd267956c58d2315f5d3ea6757cf09863c5fc703e50fbeb13a7dc849b812ef76e3cf9ca8f35a0c48498776a7478d7b4a0418e1e2b8cb9cb9731f2922aaad7f8
304 | languageName: node
305 | linkType: hard
306 |
307 | "blueimp-md5@npm:^2.10.0":
308 | version: 2.19.0
309 | resolution: "blueimp-md5@npm:2.19.0"
310 | checksum: 28095dcbd2c67152a2938006e8d7c74c3406ba6556071298f872505432feb2c13241b0476644160ee0a5220383ba94cb8ccdac0053b51f68d168728f9c382530
311 | languageName: node
312 | linkType: hard
313 |
314 | "brace-expansion@npm:^1.1.7":
315 | version: 1.1.11
316 | resolution: "brace-expansion@npm:1.1.11"
317 | dependencies:
318 | balanced-match: ^1.0.0
319 | concat-map: 0.0.1
320 | checksum: faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07
321 | languageName: node
322 | linkType: hard
323 |
324 | "brace-expansion@npm:^2.0.1":
325 | version: 2.0.1
326 | resolution: "brace-expansion@npm:2.0.1"
327 | dependencies:
328 | balanced-match: ^1.0.0
329 | checksum: a61e7cd2e8a8505e9f0036b3b6108ba5e926b4b55089eeb5550cd04a471fe216c96d4fe7e4c7f995c728c554ae20ddfc4244cad10aef255e72b62930afd233d1
330 | languageName: node
331 | linkType: hard
332 |
333 | "braces@npm:^3.0.2, braces@npm:~3.0.2":
334 | version: 3.0.2
335 | resolution: "braces@npm:3.0.2"
336 | dependencies:
337 | fill-range: ^7.0.1
338 | checksum: e2a8e769a863f3d4ee887b5fe21f63193a891c68b612ddb4b68d82d1b5f3ff9073af066c343e9867a393fe4c2555dcb33e89b937195feb9c1613d259edfcd459
339 | languageName: node
340 | linkType: hard
341 |
342 | "cacache@npm:^16.0.2":
343 | version: 16.0.7
344 | resolution: "cacache@npm:16.0.7"
345 | dependencies:
346 | "@npmcli/fs": ^2.1.0
347 | "@npmcli/move-file": ^2.0.0
348 | chownr: ^2.0.0
349 | fs-minipass: ^2.1.0
350 | glob: ^8.0.1
351 | infer-owner: ^1.0.4
352 | lru-cache: ^7.7.1
353 | minipass: ^3.1.6
354 | minipass-collect: ^1.0.2
355 | minipass-flush: ^1.0.5
356 | minipass-pipeline: ^1.2.4
357 | mkdirp: ^1.0.4
358 | p-map: ^4.0.0
359 | promise-inflight: ^1.0.1
360 | rimraf: ^3.0.2
361 | ssri: ^9.0.0
362 | tar: ^6.1.11
363 | unique-filename: ^1.1.1
364 | checksum: 2155b099b7e0f0369fb1155ca4673532ca7efe2ebdbec63acca8743580b8446b5d4fd7184626b1cb059001af77b981cdc67035c7855544d365d4f048eafca2ca
365 | languageName: node
366 | linkType: hard
367 |
368 | "callsites@npm:^4.0.0":
369 | version: 4.0.0
370 | resolution: "callsites@npm:4.0.0"
371 | checksum: ad3c3a57328a539c0d671cf1ca500abf09461b762807fc545a132026bdf87705fee9c299e1adb38b133c29201a3b04fbf4f2b90d8fa1d9e00ef507e803737cf2
372 | languageName: node
373 | linkType: hard
374 |
375 | "cbor@npm:^8.1.0":
376 | version: 8.1.0
377 | resolution: "cbor@npm:8.1.0"
378 | dependencies:
379 | nofilter: ^3.1.0
380 | checksum: a90338435dc7b45cc01461af979e3bb6ddd4f2a08584c437586039cd5f2235014c06e49d664295debbfb3514d87b2f06728092ab6aa6175e2e85e9cd7dc0c1fd
381 | languageName: node
382 | linkType: hard
383 |
384 | "chalk@npm:^5.0.0":
385 | version: 5.0.1
386 | resolution: "chalk@npm:5.0.1"
387 | checksum: 7b45300372b908f0471fbf7389ce2f5de8d85bb949026fd51a1b95b10d0ed32c7ed5aab36dd5e9d2bf3191867909b4404cef75c5f4d2d1daeeacd301dd280b76
388 | languageName: node
389 | linkType: hard
390 |
391 | "chokidar@npm:^3.5.3":
392 | version: 3.5.3
393 | resolution: "chokidar@npm:3.5.3"
394 | dependencies:
395 | anymatch: ~3.1.2
396 | braces: ~3.0.2
397 | fsevents: ~2.3.2
398 | glob-parent: ~5.1.2
399 | is-binary-path: ~2.1.0
400 | is-glob: ~4.0.1
401 | normalize-path: ~3.0.0
402 | readdirp: ~3.6.0
403 | dependenciesMeta:
404 | fsevents:
405 | optional: true
406 | checksum: b49fcde40176ba007ff361b198a2d35df60d9bb2a5aab228279eb810feae9294a6b4649ab15981304447afe1e6ffbf4788ad5db77235dc770ab777c6e771980c
407 | languageName: node
408 | linkType: hard
409 |
410 | "chownr@npm:^2.0.0":
411 | version: 2.0.0
412 | resolution: "chownr@npm:2.0.0"
413 | checksum: c57cf9dd0791e2f18a5ee9c1a299ae6e801ff58fee96dc8bfd0dcb4738a6ce58dd252a3605b1c93c6418fe4f9d5093b28ffbf4d66648cb2a9c67eaef9679be2f
414 | languageName: node
415 | linkType: hard
416 |
417 | "chunkd@npm:^2.0.1":
418 | version: 2.0.1
419 | resolution: "chunkd@npm:2.0.1"
420 | checksum: bab8cc08c752a3648984385dc6f61d751e89dbeef648d22a3b661e1d470eaa0f5182f0b4303710f13ae83d2f85144f8eb2dde7a975861d9021b5c56b881f457b
421 | languageName: node
422 | linkType: hard
423 |
424 | "ci-info@npm:^3.3.0":
425 | version: 3.3.0
426 | resolution: "ci-info@npm:3.3.0"
427 | checksum: c3d86fe374938ecda5093b1ba39acb535d8309185ba3f23587747c6a057e63f45419b406d880304dbc0e1d72392c9a33e42fe9a1e299209bc0ded5efaa232b66
428 | languageName: node
429 | linkType: hard
430 |
431 | "ci-parallel-vars@npm:^1.0.1":
432 | version: 1.0.1
433 | resolution: "ci-parallel-vars@npm:1.0.1"
434 | checksum: ae859831f7e8e3585db731b8306c336616e37bd709dad1d7775ea4c0731aefd94741dabb48201edc6827d000008fd7fb72cb977967614ee2d99d6b499f0c35fe
435 | languageName: node
436 | linkType: hard
437 |
438 | "clean-stack@npm:^2.0.0":
439 | version: 2.2.0
440 | resolution: "clean-stack@npm:2.2.0"
441 | checksum: 2ac8cd2b2f5ec986a3c743935ec85b07bc174d5421a5efc8017e1f146a1cf5f781ae962618f416352103b32c9cd7e203276e8c28241bbe946160cab16149fb68
442 | languageName: node
443 | linkType: hard
444 |
445 | "clean-stack@npm:^4.0.0":
446 | version: 4.1.0
447 | resolution: "clean-stack@npm:4.1.0"
448 | dependencies:
449 | escape-string-regexp: 5.0.0
450 | checksum: 56fdca7a67a61528676eaddce35442824700b674cf882150ac416824966f65b5e15d4ea02d1d47f4d16ad50213718c1f00ae0f6cca46aeec3fd761b49cf7204f
451 | languageName: node
452 | linkType: hard
453 |
454 | "clean-yaml-object@npm:^0.1.0":
455 | version: 0.1.0
456 | resolution: "clean-yaml-object@npm:0.1.0"
457 | checksum: 0374ad2f1fbd4984ecf56ebc62200092f6372b9ccf1b7971bb979c328fb12fe76e759fb1e8adc491c80b7b1861f9f00c7f19813dd2a0f49c88231422c70451f4
458 | languageName: node
459 | linkType: hard
460 |
461 | "cli-truncate@npm:^3.1.0":
462 | version: 3.1.0
463 | resolution: "cli-truncate@npm:3.1.0"
464 | dependencies:
465 | slice-ansi: ^5.0.0
466 | string-width: ^5.0.0
467 | checksum: c3243e41974445691c63f8b405df1d5a24049dc33d324fe448dc572e561a7b772ae982692900b1a5960901cc4fc7def25a629b9c69a4208ee89d12ab3332617a
468 | languageName: node
469 | linkType: hard
470 |
471 | "cliui@npm:^7.0.2":
472 | version: 7.0.4
473 | resolution: "cliui@npm:7.0.4"
474 | dependencies:
475 | string-width: ^4.2.0
476 | strip-ansi: ^6.0.0
477 | wrap-ansi: ^7.0.0
478 | checksum: ce2e8f578a4813806788ac399b9e866297740eecd4ad1823c27fd344d78b22c5f8597d548adbcc46f0573e43e21e751f39446c5a5e804a12aace402b7a315d7f
479 | languageName: node
480 | linkType: hard
481 |
482 | "code-excerpt@npm:^4.0.0":
483 | version: 4.0.0
484 | resolution: "code-excerpt@npm:4.0.0"
485 | dependencies:
486 | convert-to-spaces: ^2.0.1
487 | checksum: d57137d8f4825879283a828cc02a1115b56858dc54ed06c625c8f67d6685d1becd2fbaa7f0ab19ecca1f5cca03f8c97bbc1f013cab40261e4d3275032e65efe9
488 | languageName: node
489 | linkType: hard
490 |
491 | "color-convert@npm:^2.0.1":
492 | version: 2.0.1
493 | resolution: "color-convert@npm:2.0.1"
494 | dependencies:
495 | color-name: ~1.1.4
496 | checksum: 79e6bdb9fd479a205c71d89574fccfb22bd9053bd98c6c4d870d65c132e5e904e6034978e55b43d69fcaa7433af2016ee203ce76eeba9cfa554b373e7f7db336
497 | languageName: node
498 | linkType: hard
499 |
500 | "color-name@npm:~1.1.4":
501 | version: 1.1.4
502 | resolution: "color-name@npm:1.1.4"
503 | checksum: b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610
504 | languageName: node
505 | linkType: hard
506 |
507 | "color-support@npm:^1.1.3":
508 | version: 1.1.3
509 | resolution: "color-support@npm:1.1.3"
510 | bin:
511 | color-support: bin.js
512 | checksum: 9b7356817670b9a13a26ca5af1c21615463b500783b739b7634a0c2047c16cef4b2865d7576875c31c3cddf9dd621fa19285e628f20198b233a5cfdda6d0793b
513 | languageName: node
514 | linkType: hard
515 |
516 | "common-path-prefix@npm:^3.0.0":
517 | version: 3.0.0
518 | resolution: "common-path-prefix@npm:3.0.0"
519 | checksum: fdb3c4f54e51e70d417ccd950c07f757582de800c0678ca388aedefefc84982039f346f9fd9a1252d08d2da9e9ef4019f580a1d1d3a10da031e4bb3c924c5818
520 | languageName: node
521 | linkType: hard
522 |
523 | "concat-map@npm:0.0.1":
524 | version: 0.0.1
525 | resolution: "concat-map@npm:0.0.1"
526 | checksum: 902a9f5d8967a3e2faf138d5cb784b9979bad2e6db5357c5b21c568df4ebe62bcb15108af1b2253744844eb964fc023fbd9afbbbb6ddd0bcc204c6fb5b7bf3af
527 | languageName: node
528 | linkType: hard
529 |
530 | "concordance@npm:^5.0.4":
531 | version: 5.0.4
532 | resolution: "concordance@npm:5.0.4"
533 | dependencies:
534 | date-time: ^3.1.0
535 | esutils: ^2.0.3
536 | fast-diff: ^1.2.0
537 | js-string-escape: ^1.0.1
538 | lodash: ^4.17.15
539 | md5-hex: ^3.0.1
540 | semver: ^7.3.2
541 | well-known-symbols: ^2.0.0
542 | checksum: 749153ba711492feb7c3d2f5bb04c107157440b3e39509bd5dd19ee7b3ac751d1e4cd75796d9f702e0a713312dbc661421c68aa4a2c34d5f6d91f47e3a1c64a6
543 | languageName: node
544 | linkType: hard
545 |
546 | "console-control-strings@npm:^1.1.0":
547 | version: 1.1.0
548 | resolution: "console-control-strings@npm:1.1.0"
549 | checksum: 8755d76787f94e6cf79ce4666f0c5519906d7f5b02d4b884cf41e11dcd759ed69c57da0670afd9236d229a46e0f9cf519db0cd829c6dca820bb5a5c3def584ed
550 | languageName: node
551 | linkType: hard
552 |
553 | "convert-to-spaces@npm:^2.0.1":
554 | version: 2.0.1
555 | resolution: "convert-to-spaces@npm:2.0.1"
556 | checksum: bbb324e5916fe9866f65c0ff5f9c1ea933764d0bdb09fccaf59542e40545ed483db6b2339c6d9eb56a11965a58f1a6038f3174f0e2fb7601343c7107ca5e2751
557 | languageName: node
558 | linkType: hard
559 |
560 | "currently-unhandled@npm:^0.4.1":
561 | version: 0.4.1
562 | resolution: "currently-unhandled@npm:0.4.1"
563 | dependencies:
564 | array-find-index: ^1.0.1
565 | checksum: 1f59fe10b5339b54b1a1eee110022f663f3495cf7cf2f480686e89edc7fa8bfe42dbab4b54f85034bc8b092a76cc7becbc2dad4f9adad332ab5831bec39ad540
566 | languageName: node
567 | linkType: hard
568 |
569 | "date-time@npm:^3.1.0":
570 | version: 3.1.0
571 | resolution: "date-time@npm:3.1.0"
572 | dependencies:
573 | time-zone: ^1.0.0
574 | checksum: f9cfcd1b15dfeabab15c0b9d18eb9e4e2d9d4371713564178d46a8f91ad577a290b5178b80050718d02d9c0cf646f8a875011e12d1ed05871e9f72c72c8a8fe6
575 | languageName: node
576 | linkType: hard
577 |
578 | "debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.3.3":
579 | version: 4.3.4
580 | resolution: "debug@npm:4.3.4"
581 | dependencies:
582 | ms: 2.1.2
583 | peerDependenciesMeta:
584 | supports-color:
585 | optional: true
586 | checksum: 3dbad3f94ea64f34431a9cbf0bafb61853eda57bff2880036153438f50fb5a84f27683ba0d8e5426bf41a8c6ff03879488120cf5b3a761e77953169c0600a708
587 | languageName: node
588 | linkType: hard
589 |
590 | "del@npm:^6.0.0":
591 | version: 6.0.0
592 | resolution: "del@npm:6.0.0"
593 | dependencies:
594 | globby: ^11.0.1
595 | graceful-fs: ^4.2.4
596 | is-glob: ^4.0.1
597 | is-path-cwd: ^2.2.0
598 | is-path-inside: ^3.0.2
599 | p-map: ^4.0.0
600 | rimraf: ^3.0.2
601 | slash: ^3.0.0
602 | checksum: 5742891627e91aaf62385714025233f4664da28bc55b6ab825649dcdea4691fed3cf329a2b1913fd2d2612e693e99e08a03c84cac7f36ef54bacac9390520192
603 | languageName: node
604 | linkType: hard
605 |
606 | "delegates@npm:^1.0.0":
607 | version: 1.0.0
608 | resolution: "delegates@npm:1.0.0"
609 | checksum: a51744d9b53c164ba9c0492471a1a2ffa0b6727451bdc89e31627fdf4adda9d51277cfcbfb20f0a6f08ccb3c436f341df3e92631a3440226d93a8971724771fd
610 | languageName: node
611 | linkType: hard
612 |
613 | "depd@npm:^1.1.2":
614 | version: 1.1.2
615 | resolution: "depd@npm:1.1.2"
616 | checksum: 6b406620d269619852885ce15965272b829df6f409724415e0002c8632ab6a8c0a08ec1f0bd2add05dc7bd7507606f7e2cc034fa24224ab829580040b835ecd9
617 | languageName: node
618 | linkType: hard
619 |
620 | "dir-glob@npm:^3.0.1":
621 | version: 3.0.1
622 | resolution: "dir-glob@npm:3.0.1"
623 | dependencies:
624 | path-type: ^4.0.0
625 | checksum: fa05e18324510d7283f55862f3161c6759a3f2f8dbce491a2fc14c8324c498286c54282c1f0e933cb930da8419b30679389499b919122952a4f8592362ef4615
626 | languageName: node
627 | linkType: hard
628 |
629 | "eastasianwidth@npm:^0.2.0":
630 | version: 0.2.0
631 | resolution: "eastasianwidth@npm:0.2.0"
632 | checksum: 7d00d7cd8e49b9afa762a813faac332dee781932d6f2c848dc348939c4253f1d4564341b7af1d041853bc3f32c2ef141b58e0a4d9862c17a7f08f68df1e0f1ed
633 | languageName: node
634 | linkType: hard
635 |
636 | "emittery@npm:^0.10.1":
637 | version: 0.10.2
638 | resolution: "emittery@npm:0.10.2"
639 | checksum: ee3e21788b043b90885b18ea756ec3105c1cedc50b29709c92b01e239c7e55345d4bb6d3aef4ddbaf528eef448a40b3bb831bad9ee0fc9c25cbf1367ab1ab5ac
640 | languageName: node
641 | linkType: hard
642 |
643 | "emoji-regex@npm:^8.0.0":
644 | version: 8.0.0
645 | resolution: "emoji-regex@npm:8.0.0"
646 | checksum: d4c5c39d5a9868b5fa152f00cada8a936868fd3367f33f71be515ecee4c803132d11b31a6222b2571b1e5f7e13890156a94880345594d0ce7e3c9895f560f192
647 | languageName: node
648 | linkType: hard
649 |
650 | "emoji-regex@npm:^9.2.2":
651 | version: 9.2.2
652 | resolution: "emoji-regex@npm:9.2.2"
653 | checksum: 8487182da74aabd810ac6d6f1994111dfc0e331b01271ae01ec1eb0ad7b5ecc2bbbbd2f053c05cb55a1ac30449527d819bbfbf0e3de1023db308cbcb47f86601
654 | languageName: node
655 | linkType: hard
656 |
657 | "encoding@npm:^0.1.13":
658 | version: 0.1.13
659 | resolution: "encoding@npm:0.1.13"
660 | dependencies:
661 | iconv-lite: ^0.6.2
662 | checksum: bb98632f8ffa823996e508ce6a58ffcf5856330fde839ae42c9e1f436cc3b5cc651d4aeae72222916545428e54fd0f6aa8862fd8d25bdbcc4589f1e3f3715e7f
663 | languageName: node
664 | linkType: hard
665 |
666 | "env-paths@npm:^2.2.0":
667 | version: 2.2.1
668 | resolution: "env-paths@npm:2.2.1"
669 | checksum: 65b5df55a8bab92229ab2b40dad3b387fad24613263d103a97f91c9fe43ceb21965cd3392b1ccb5d77088021e525c4e0481adb309625d0cb94ade1d1fb8dc17e
670 | languageName: node
671 | linkType: hard
672 |
673 | "err-code@npm:^2.0.2":
674 | version: 2.0.3
675 | resolution: "err-code@npm:2.0.3"
676 | checksum: 8b7b1be20d2de12d2255c0bc2ca638b7af5171142693299416e6a9339bd7d88fc8d7707d913d78e0993176005405a236b066b45666b27b797252c771156ace54
677 | languageName: node
678 | linkType: hard
679 |
680 | "esbuild-android-64@npm:0.14.38":
681 | version: 0.14.38
682 | resolution: "esbuild-android-64@npm:0.14.38"
683 | conditions: os=android & cpu=x64
684 | languageName: node
685 | linkType: hard
686 |
687 | "esbuild-android-arm64@npm:0.14.38":
688 | version: 0.14.38
689 | resolution: "esbuild-android-arm64@npm:0.14.38"
690 | conditions: os=android & cpu=arm64
691 | languageName: node
692 | linkType: hard
693 |
694 | "esbuild-darwin-64@npm:0.14.38":
695 | version: 0.14.38
696 | resolution: "esbuild-darwin-64@npm:0.14.38"
697 | conditions: os=darwin & cpu=x64
698 | languageName: node
699 | linkType: hard
700 |
701 | "esbuild-darwin-arm64@npm:0.14.38":
702 | version: 0.14.38
703 | resolution: "esbuild-darwin-arm64@npm:0.14.38"
704 | conditions: os=darwin & cpu=arm64
705 | languageName: node
706 | linkType: hard
707 |
708 | "esbuild-freebsd-64@npm:0.14.38":
709 | version: 0.14.38
710 | resolution: "esbuild-freebsd-64@npm:0.14.38"
711 | conditions: os=freebsd & cpu=x64
712 | languageName: node
713 | linkType: hard
714 |
715 | "esbuild-freebsd-arm64@npm:0.14.38":
716 | version: 0.14.38
717 | resolution: "esbuild-freebsd-arm64@npm:0.14.38"
718 | conditions: os=freebsd & cpu=arm64
719 | languageName: node
720 | linkType: hard
721 |
722 | "esbuild-linux-32@npm:0.14.38":
723 | version: 0.14.38
724 | resolution: "esbuild-linux-32@npm:0.14.38"
725 | conditions: os=linux & cpu=ia32
726 | languageName: node
727 | linkType: hard
728 |
729 | "esbuild-linux-64@npm:0.14.38":
730 | version: 0.14.38
731 | resolution: "esbuild-linux-64@npm:0.14.38"
732 | conditions: os=linux & cpu=x64
733 | languageName: node
734 | linkType: hard
735 |
736 | "esbuild-linux-arm64@npm:0.14.38":
737 | version: 0.14.38
738 | resolution: "esbuild-linux-arm64@npm:0.14.38"
739 | conditions: os=linux & cpu=arm64
740 | languageName: node
741 | linkType: hard
742 |
743 | "esbuild-linux-arm@npm:0.14.38":
744 | version: 0.14.38
745 | resolution: "esbuild-linux-arm@npm:0.14.38"
746 | conditions: os=linux & cpu=arm
747 | languageName: node
748 | linkType: hard
749 |
750 | "esbuild-linux-mips64le@npm:0.14.38":
751 | version: 0.14.38
752 | resolution: "esbuild-linux-mips64le@npm:0.14.38"
753 | conditions: os=linux & cpu=mips64el
754 | languageName: node
755 | linkType: hard
756 |
757 | "esbuild-linux-ppc64le@npm:0.14.38":
758 | version: 0.14.38
759 | resolution: "esbuild-linux-ppc64le@npm:0.14.38"
760 | conditions: os=linux & cpu=ppc64
761 | languageName: node
762 | linkType: hard
763 |
764 | "esbuild-linux-riscv64@npm:0.14.38":
765 | version: 0.14.38
766 | resolution: "esbuild-linux-riscv64@npm:0.14.38"
767 | conditions: os=linux & cpu=riscv64
768 | languageName: node
769 | linkType: hard
770 |
771 | "esbuild-linux-s390x@npm:0.14.38":
772 | version: 0.14.38
773 | resolution: "esbuild-linux-s390x@npm:0.14.38"
774 | conditions: os=linux & cpu=s390x
775 | languageName: node
776 | linkType: hard
777 |
778 | "esbuild-netbsd-64@npm:0.14.38":
779 | version: 0.14.38
780 | resolution: "esbuild-netbsd-64@npm:0.14.38"
781 | conditions: os=netbsd & cpu=x64
782 | languageName: node
783 | linkType: hard
784 |
785 | "esbuild-openbsd-64@npm:0.14.38":
786 | version: 0.14.38
787 | resolution: "esbuild-openbsd-64@npm:0.14.38"
788 | conditions: os=openbsd & cpu=x64
789 | languageName: node
790 | linkType: hard
791 |
792 | "esbuild-plugin-globals@npm:^0.1.1":
793 | version: 0.1.1
794 | resolution: "esbuild-plugin-globals@npm:0.1.1"
795 | checksum: 07460a455174e280829e172096b70422a945bcaba0efbe2e71a88ccdcc194e0251c7a7cdc27fd5dda3420777dc6f7ee6312e1e3167af2627a67a39be7d7c373d
796 | languageName: node
797 | linkType: hard
798 |
799 | "esbuild-sunos-64@npm:0.14.38":
800 | version: 0.14.38
801 | resolution: "esbuild-sunos-64@npm:0.14.38"
802 | conditions: os=sunos & cpu=x64
803 | languageName: node
804 | linkType: hard
805 |
806 | "esbuild-windows-32@npm:0.14.38":
807 | version: 0.14.38
808 | resolution: "esbuild-windows-32@npm:0.14.38"
809 | conditions: os=win32 & cpu=ia32
810 | languageName: node
811 | linkType: hard
812 |
813 | "esbuild-windows-64@npm:0.14.38":
814 | version: 0.14.38
815 | resolution: "esbuild-windows-64@npm:0.14.38"
816 | conditions: os=win32 & cpu=x64
817 | languageName: node
818 | linkType: hard
819 |
820 | "esbuild-windows-arm64@npm:0.14.38":
821 | version: 0.14.38
822 | resolution: "esbuild-windows-arm64@npm:0.14.38"
823 | conditions: os=win32 & cpu=arm64
824 | languageName: node
825 | linkType: hard
826 |
827 | "esbuild@npm:^0.14.38":
828 | version: 0.14.38
829 | resolution: "esbuild@npm:0.14.38"
830 | dependencies:
831 | esbuild-android-64: 0.14.38
832 | esbuild-android-arm64: 0.14.38
833 | esbuild-darwin-64: 0.14.38
834 | esbuild-darwin-arm64: 0.14.38
835 | esbuild-freebsd-64: 0.14.38
836 | esbuild-freebsd-arm64: 0.14.38
837 | esbuild-linux-32: 0.14.38
838 | esbuild-linux-64: 0.14.38
839 | esbuild-linux-arm: 0.14.38
840 | esbuild-linux-arm64: 0.14.38
841 | esbuild-linux-mips64le: 0.14.38
842 | esbuild-linux-ppc64le: 0.14.38
843 | esbuild-linux-riscv64: 0.14.38
844 | esbuild-linux-s390x: 0.14.38
845 | esbuild-netbsd-64: 0.14.38
846 | esbuild-openbsd-64: 0.14.38
847 | esbuild-sunos-64: 0.14.38
848 | esbuild-windows-32: 0.14.38
849 | esbuild-windows-64: 0.14.38
850 | esbuild-windows-arm64: 0.14.38
851 | dependenciesMeta:
852 | esbuild-android-64:
853 | optional: true
854 | esbuild-android-arm64:
855 | optional: true
856 | esbuild-darwin-64:
857 | optional: true
858 | esbuild-darwin-arm64:
859 | optional: true
860 | esbuild-freebsd-64:
861 | optional: true
862 | esbuild-freebsd-arm64:
863 | optional: true
864 | esbuild-linux-32:
865 | optional: true
866 | esbuild-linux-64:
867 | optional: true
868 | esbuild-linux-arm:
869 | optional: true
870 | esbuild-linux-arm64:
871 | optional: true
872 | esbuild-linux-mips64le:
873 | optional: true
874 | esbuild-linux-ppc64le:
875 | optional: true
876 | esbuild-linux-riscv64:
877 | optional: true
878 | esbuild-linux-s390x:
879 | optional: true
880 | esbuild-netbsd-64:
881 | optional: true
882 | esbuild-openbsd-64:
883 | optional: true
884 | esbuild-sunos-64:
885 | optional: true
886 | esbuild-windows-32:
887 | optional: true
888 | esbuild-windows-64:
889 | optional: true
890 | esbuild-windows-arm64:
891 | optional: true
892 | bin:
893 | esbuild: bin/esbuild
894 | checksum: d7523a36bd28016c010829c527386dbc0c6b9f514920abf5ac8003f346665161aa61026fd6822c5091fc1c1af52fe26c9281a81740fc06f2994cdbb7c2880297
895 | languageName: node
896 | linkType: hard
897 |
898 | "escalade@npm:^3.1.1":
899 | version: 3.1.1
900 | resolution: "escalade@npm:3.1.1"
901 | checksum: a3e2a99f07acb74b3ad4989c48ca0c3140f69f923e56d0cba0526240ee470b91010f9d39001f2a4a313841d237ede70a729e92125191ba5d21e74b106800b133
902 | languageName: node
903 | linkType: hard
904 |
905 | "escape-string-regexp@npm:5.0.0, escape-string-regexp@npm:^5.0.0":
906 | version: 5.0.0
907 | resolution: "escape-string-regexp@npm:5.0.0"
908 | checksum: 20daabe197f3cb198ec28546deebcf24b3dbb1a5a269184381b3116d12f0532e06007f4bc8da25669d6a7f8efb68db0758df4cd981f57bc5b57f521a3e12c59e
909 | languageName: node
910 | linkType: hard
911 |
912 | "escape-string-regexp@npm:^2.0.0":
913 | version: 2.0.0
914 | resolution: "escape-string-regexp@npm:2.0.0"
915 | checksum: 9f8a2d5743677c16e85c810e3024d54f0c8dea6424fad3c79ef6666e81dd0846f7437f5e729dfcdac8981bc9e5294c39b4580814d114076b8d36318f46ae4395
916 | languageName: node
917 | linkType: hard
918 |
919 | "esprima@npm:^4.0.0":
920 | version: 4.0.1
921 | resolution: "esprima@npm:4.0.1"
922 | bin:
923 | esparse: ./bin/esparse.js
924 | esvalidate: ./bin/esvalidate.js
925 | checksum: b45bc805a613dbea2835278c306b91aff6173c8d034223fa81498c77dcbce3b2931bf6006db816f62eacd9fd4ea975dfd85a5b7f3c6402cfd050d4ca3c13a628
926 | languageName: node
927 | linkType: hard
928 |
929 | "esutils@npm:^2.0.3":
930 | version: 2.0.3
931 | resolution: "esutils@npm:2.0.3"
932 | checksum: 22b5b08f74737379a840b8ed2036a5fb35826c709ab000683b092d9054e5c2a82c27818f12604bfc2a9a76b90b6834ef081edbc1c7ae30d1627012e067c6ec87
933 | languageName: node
934 | linkType: hard
935 |
936 | "fast-diff@npm:^1.2.0":
937 | version: 1.2.0
938 | resolution: "fast-diff@npm:1.2.0"
939 | checksum: 1b5306eaa9e826564d9e5ffcd6ebd881eb5f770b3f977fcbf38f05c824e42172b53c79920e8429c54eb742ce15a0caf268b0fdd5b38f6de52234c4a8368131ae
940 | languageName: node
941 | linkType: hard
942 |
943 | "fast-glob@npm:^3.2.11, fast-glob@npm:^3.2.9":
944 | version: 3.2.11
945 | resolution: "fast-glob@npm:3.2.11"
946 | dependencies:
947 | "@nodelib/fs.stat": ^2.0.2
948 | "@nodelib/fs.walk": ^1.2.3
949 | glob-parent: ^5.1.2
950 | merge2: ^1.3.0
951 | micromatch: ^4.0.4
952 | checksum: f473105324a7780a20c06de842e15ddbb41d3cb7e71d1e4fe6e8373204f22245d54f5ab9e2061e6a1c613047345954d29b022e0e76f5c28b1df9858179a0e6d7
953 | languageName: node
954 | linkType: hard
955 |
956 | "fastq@npm:^1.6.0":
957 | version: 1.13.0
958 | resolution: "fastq@npm:1.13.0"
959 | dependencies:
960 | reusify: ^1.0.4
961 | checksum: 32cf15c29afe622af187d12fc9cd93e160a0cb7c31a3bb6ace86b7dea3b28e7b72acde89c882663f307b2184e14782c6c664fa315973c03626c7d4bff070bb0b
962 | languageName: node
963 | linkType: hard
964 |
965 | "figures@npm:^4.0.0":
966 | version: 4.0.1
967 | resolution: "figures@npm:4.0.1"
968 | dependencies:
969 | escape-string-regexp: ^5.0.0
970 | is-unicode-supported: ^1.2.0
971 | checksum: 08564c70ec6be8dbd26e24e4f35bacb8d9beb729b3b7faa9cd7ad54f5232b7f9a39f788a847ec45677664d568c86323001d1042482d089c0d0f311e197ad1148
972 | languageName: node
973 | linkType: hard
974 |
975 | "fill-range@npm:^7.0.1":
976 | version: 7.0.1
977 | resolution: "fill-range@npm:7.0.1"
978 | dependencies:
979 | to-regex-range: ^5.0.1
980 | checksum: cc283f4e65b504259e64fd969bcf4def4eb08d85565e906b7d36516e87819db52029a76b6363d0f02d0d532f0033c9603b9e2d943d56ee3b0d4f7ad3328ff917
981 | languageName: node
982 | linkType: hard
983 |
984 | "find-up@npm:^6.0.0":
985 | version: 6.3.0
986 | resolution: "find-up@npm:6.3.0"
987 | dependencies:
988 | locate-path: ^7.1.0
989 | path-exists: ^5.0.0
990 | checksum: 9a21b7f9244a420e54c6df95b4f6fc3941efd3c3e5476f8274eb452f6a85706e7a6a90de71353ee4f091fcb4593271a6f92810a324ec542650398f928783c280
991 | languageName: node
992 | linkType: hard
993 |
994 | "fs-minipass@npm:^2.0.0, fs-minipass@npm:^2.1.0":
995 | version: 2.1.0
996 | resolution: "fs-minipass@npm:2.1.0"
997 | dependencies:
998 | minipass: ^3.0.0
999 | checksum: 1b8d128dae2ac6cc94230cc5ead341ba3e0efaef82dab46a33d171c044caaa6ca001364178d42069b2809c35a1c3c35079a32107c770e9ffab3901b59af8c8b1
1000 | languageName: node
1001 | linkType: hard
1002 |
1003 | "fs.realpath@npm:^1.0.0":
1004 | version: 1.0.0
1005 | resolution: "fs.realpath@npm:1.0.0"
1006 | checksum: 99ddea01a7e75aa276c250a04eedeffe5662bce66c65c07164ad6264f9de18fb21be9433ead460e54cff20e31721c811f4fb5d70591799df5f85dce6d6746fd0
1007 | languageName: node
1008 | linkType: hard
1009 |
1010 | "fsevents@npm:~2.3.2":
1011 | version: 2.3.2
1012 | resolution: "fsevents@npm:2.3.2"
1013 | dependencies:
1014 | node-gyp: latest
1015 | checksum: 97ade64e75091afee5265e6956cb72ba34db7819b4c3e94c431d4be2b19b8bb7a2d4116da417950c3425f17c8fe693d25e20212cac583ac1521ad066b77ae31f
1016 | conditions: os=darwin
1017 | languageName: node
1018 | linkType: hard
1019 |
1020 | "fsevents@patch:fsevents@~2.3.2#~builtin":
1021 | version: 2.3.2
1022 | resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin::version=2.3.2&hash=18f3a7"
1023 | dependencies:
1024 | node-gyp: latest
1025 | conditions: os=darwin
1026 | languageName: node
1027 | linkType: hard
1028 |
1029 | "gauge@npm:^4.0.3":
1030 | version: 4.0.4
1031 | resolution: "gauge@npm:4.0.4"
1032 | dependencies:
1033 | aproba: ^1.0.3 || ^2.0.0
1034 | color-support: ^1.1.3
1035 | console-control-strings: ^1.1.0
1036 | has-unicode: ^2.0.1
1037 | signal-exit: ^3.0.7
1038 | string-width: ^4.2.3
1039 | strip-ansi: ^6.0.1
1040 | wide-align: ^1.1.5
1041 | checksum: 788b6bfe52f1dd8e263cda800c26ac0ca2ff6de0b6eee2fe0d9e3abf15e149b651bd27bf5226be10e6e3edb5c4e5d5985a5a1a98137e7a892f75eff76467ad2d
1042 | languageName: node
1043 | linkType: hard
1044 |
1045 | "get-caller-file@npm:^2.0.5":
1046 | version: 2.0.5
1047 | resolution: "get-caller-file@npm:2.0.5"
1048 | checksum: b9769a836d2a98c3ee734a88ba712e62703f1df31b94b784762c433c27a386dd6029ff55c2a920c392e33657d80191edbf18c61487e198844844516f843496b9
1049 | languageName: node
1050 | linkType: hard
1051 |
1052 | "glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2":
1053 | version: 5.1.2
1054 | resolution: "glob-parent@npm:5.1.2"
1055 | dependencies:
1056 | is-glob: ^4.0.1
1057 | checksum: f4f2bfe2425296e8a47e36864e4f42be38a996db40420fe434565e4480e3322f18eb37589617a98640c5dc8fdec1a387007ee18dbb1f3f5553409c34d17f425e
1058 | languageName: node
1059 | linkType: hard
1060 |
1061 | "glob@npm:^7.1.3, glob@npm:^7.1.4":
1062 | version: 7.2.0
1063 | resolution: "glob@npm:7.2.0"
1064 | dependencies:
1065 | fs.realpath: ^1.0.0
1066 | inflight: ^1.0.4
1067 | inherits: 2
1068 | minimatch: ^3.0.4
1069 | once: ^1.3.0
1070 | path-is-absolute: ^1.0.0
1071 | checksum: 78a8ea942331f08ed2e055cb5b9e40fe6f46f579d7fd3d694f3412fe5db23223d29b7fee1575440202e9a7ff9a72ab106a39fee39934c7bedafe5e5f8ae20134
1072 | languageName: node
1073 | linkType: hard
1074 |
1075 | "glob@npm:^8.0.1":
1076 | version: 8.0.1
1077 | resolution: "glob@npm:8.0.1"
1078 | dependencies:
1079 | fs.realpath: ^1.0.0
1080 | inflight: ^1.0.4
1081 | inherits: 2
1082 | minimatch: ^5.0.1
1083 | once: ^1.3.0
1084 | path-is-absolute: ^1.0.0
1085 | checksum: 7ac782f3ef1c08005884447479e68ceb0ad56997eb2003e1e9aefae71bad3cb48eb7c49190d3d6736f2ffcd8af4985d53a46831b3d5e0052cc5756822a38b61a
1086 | languageName: node
1087 | linkType: hard
1088 |
1089 | "globby@npm:^11.0.1":
1090 | version: 11.1.0
1091 | resolution: "globby@npm:11.1.0"
1092 | dependencies:
1093 | array-union: ^2.1.0
1094 | dir-glob: ^3.0.1
1095 | fast-glob: ^3.2.9
1096 | ignore: ^5.2.0
1097 | merge2: ^1.4.1
1098 | slash: ^3.0.0
1099 | checksum: b4be8885e0cfa018fc783792942d53926c35c50b3aefd3fdcfb9d22c627639dc26bd2327a40a0b74b074100ce95bb7187bfeae2f236856aa3de183af7a02aea6
1100 | languageName: node
1101 | linkType: hard
1102 |
1103 | "globby@npm:^13.1.1":
1104 | version: 13.1.1
1105 | resolution: "globby@npm:13.1.1"
1106 | dependencies:
1107 | dir-glob: ^3.0.1
1108 | fast-glob: ^3.2.11
1109 | ignore: ^5.2.0
1110 | merge2: ^1.4.1
1111 | slash: ^4.0.0
1112 | checksum: e6c43409c6c31b374fbd1c01a8c1811de52336928be9c697e472d2a89a156c9cbf1fb33863755c0447b4db16485858aa57f16628d66a6b7c7131669c9fbe76cd
1113 | languageName: node
1114 | linkType: hard
1115 |
1116 | "graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6":
1117 | version: 4.2.10
1118 | resolution: "graceful-fs@npm:4.2.10"
1119 | checksum: 3f109d70ae123951905d85032ebeae3c2a5a7a997430df00ea30df0e3a6c60cf6689b109654d6fdacd28810a053348c4d14642da1d075049e6be1ba5216218da
1120 | languageName: node
1121 | linkType: hard
1122 |
1123 | "has-unicode@npm:^2.0.1":
1124 | version: 2.0.1
1125 | resolution: "has-unicode@npm:2.0.1"
1126 | checksum: 1eab07a7436512db0be40a710b29b5dc21fa04880b7f63c9980b706683127e3c1b57cb80ea96d47991bdae2dfe479604f6a1ba410106ee1046a41d1bd0814400
1127 | languageName: node
1128 | linkType: hard
1129 |
1130 | "http-cache-semantics@npm:^4.1.0":
1131 | version: 4.1.0
1132 | resolution: "http-cache-semantics@npm:4.1.0"
1133 | checksum: 974de94a81c5474be07f269f9fd8383e92ebb5a448208223bfb39e172a9dbc26feff250192ecc23b9593b3f92098e010406b0f24bd4d588d631f80214648ed42
1134 | languageName: node
1135 | linkType: hard
1136 |
1137 | "http-proxy-agent@npm:^5.0.0":
1138 | version: 5.0.0
1139 | resolution: "http-proxy-agent@npm:5.0.0"
1140 | dependencies:
1141 | "@tootallnate/once": 2
1142 | agent-base: 6
1143 | debug: 4
1144 | checksum: e2ee1ff1656a131953839b2a19cd1f3a52d97c25ba87bd2559af6ae87114abf60971e498021f9b73f9fd78aea8876d1fb0d4656aac8a03c6caa9fc175f22b786
1145 | languageName: node
1146 | linkType: hard
1147 |
1148 | "https-proxy-agent@npm:^5.0.0":
1149 | version: 5.0.1
1150 | resolution: "https-proxy-agent@npm:5.0.1"
1151 | dependencies:
1152 | agent-base: 6
1153 | debug: 4
1154 | checksum: 571fccdf38184f05943e12d37d6ce38197becdd69e58d03f43637f7fa1269cf303a7d228aa27e5b27bbd3af8f09fd938e1c91dcfefff2df7ba77c20ed8dfc765
1155 | languageName: node
1156 | linkType: hard
1157 |
1158 | "humanize-ms@npm:^1.2.1":
1159 | version: 1.2.1
1160 | resolution: "humanize-ms@npm:1.2.1"
1161 | dependencies:
1162 | ms: ^2.0.0
1163 | checksum: 9c7a74a2827f9294c009266c82031030eae811ca87b0da3dceb8d6071b9bde22c9f3daef0469c3c533cc67a97d8a167cd9fc0389350e5f415f61a79b171ded16
1164 | languageName: node
1165 | linkType: hard
1166 |
1167 | "iconv-lite@npm:^0.6.2":
1168 | version: 0.6.3
1169 | resolution: "iconv-lite@npm:0.6.3"
1170 | dependencies:
1171 | safer-buffer: ">= 2.1.2 < 3.0.0"
1172 | checksum: 3f60d47a5c8fc3313317edfd29a00a692cc87a19cac0159e2ce711d0ebc9019064108323b5e493625e25594f11c6236647d8e256fbe7a58f4a3b33b89e6d30bf
1173 | languageName: node
1174 | linkType: hard
1175 |
1176 | "ignore-by-default@npm:^2.0.0":
1177 | version: 2.0.0
1178 | resolution: "ignore-by-default@npm:2.0.0"
1179 | checksum: c9934ea2ad751ded6016c4155cdd72ad5e7c6220cb1113ee080c6ac86f72ab0c6abbebbd53bf678595c616eccf0974d6275dd5818a64301f75d602ba1d15f5bb
1180 | languageName: node
1181 | linkType: hard
1182 |
1183 | "ignore@npm:^5.2.0":
1184 | version: 5.2.0
1185 | resolution: "ignore@npm:5.2.0"
1186 | checksum: 6b1f926792d614f64c6c83da3a1f9c83f6196c2839aa41e1e32dd7b8d174cef2e329d75caabb62cb61ce9dc432f75e67d07d122a037312db7caa73166a1bdb77
1187 | languageName: node
1188 | linkType: hard
1189 |
1190 | "imurmurhash@npm:^0.1.4":
1191 | version: 0.1.4
1192 | resolution: "imurmurhash@npm:0.1.4"
1193 | checksum: 7cae75c8cd9a50f57dadd77482359f659eaebac0319dd9368bcd1714f55e65badd6929ca58569da2b6494ef13fdd5598cd700b1eba23f8b79c5f19d195a3ecf7
1194 | languageName: node
1195 | linkType: hard
1196 |
1197 | "indent-string@npm:^4.0.0":
1198 | version: 4.0.0
1199 | resolution: "indent-string@npm:4.0.0"
1200 | checksum: 824cfb9929d031dabf059bebfe08cf3137365e112019086ed3dcff6a0a7b698cb80cf67ccccde0e25b9e2d7527aa6cc1fed1ac490c752162496caba3e6699612
1201 | languageName: node
1202 | linkType: hard
1203 |
1204 | "indent-string@npm:^5.0.0":
1205 | version: 5.0.0
1206 | resolution: "indent-string@npm:5.0.0"
1207 | checksum: e466c27b6373440e6d84fbc19e750219ce25865cb82d578e41a6053d727e5520dc5725217d6eb1cc76005a1bb1696a0f106d84ce7ebda3033b963a38583fb3b3
1208 | languageName: node
1209 | linkType: hard
1210 |
1211 | "infer-owner@npm:^1.0.4":
1212 | version: 1.0.4
1213 | resolution: "infer-owner@npm:1.0.4"
1214 | checksum: 181e732764e4a0611576466b4b87dac338972b839920b2a8cde43642e4ed6bd54dc1fb0b40874728f2a2df9a1b097b8ff83b56d5f8f8e3927f837fdcb47d8a89
1215 | languageName: node
1216 | linkType: hard
1217 |
1218 | "inflight@npm:^1.0.4":
1219 | version: 1.0.6
1220 | resolution: "inflight@npm:1.0.6"
1221 | dependencies:
1222 | once: ^1.3.0
1223 | wrappy: 1
1224 | checksum: f4f76aa072ce19fae87ce1ef7d221e709afb59d445e05d47fba710e85470923a75de35bfae47da6de1b18afc3ce83d70facf44cfb0aff89f0a3f45c0a0244dfd
1225 | languageName: node
1226 | linkType: hard
1227 |
1228 | "inherits@npm:2, inherits@npm:^2.0.3":
1229 | version: 2.0.4
1230 | resolution: "inherits@npm:2.0.4"
1231 | checksum: 4a48a733847879d6cf6691860a6b1e3f0f4754176e4d71494c41f3475553768b10f84b5ce1d40fbd0e34e6bfbb864ee35858ad4dd2cf31e02fc4a154b724d7f1
1232 | languageName: node
1233 | linkType: hard
1234 |
1235 | "ip@npm:^1.1.5":
1236 | version: 1.1.5
1237 | resolution: "ip@npm:1.1.5"
1238 | checksum: 30133981f082a060a32644f6a7746e9ba7ac9e2bc07ecc8bbdda3ee8ca9bec1190724c390e45a1ee7695e7edfd2a8f7dda2c104ec5f7ac5068c00648504c7e5a
1239 | languageName: node
1240 | linkType: hard
1241 |
1242 | "irregular-plurals@npm:^3.3.0":
1243 | version: 3.3.0
1244 | resolution: "irregular-plurals@npm:3.3.0"
1245 | checksum: 1282d8adfb00a9718655ce21e5b096d4b31d2115c817a30e1e3254648ae4ac0f84d706cd0cad2a93c64f4bb5c5572ea8f63fcc9766f005a5362031c56d9e77b5
1246 | languageName: node
1247 | linkType: hard
1248 |
1249 | "is-binary-path@npm:~2.1.0":
1250 | version: 2.1.0
1251 | resolution: "is-binary-path@npm:2.1.0"
1252 | dependencies:
1253 | binary-extensions: ^2.0.0
1254 | checksum: 84192eb88cff70d320426f35ecd63c3d6d495da9d805b19bc65b518984b7c0760280e57dbf119b7e9be6b161784a5a673ab2c6abe83abb5198a432232ad5b35c
1255 | languageName: node
1256 | linkType: hard
1257 |
1258 | "is-error@npm:^2.2.2":
1259 | version: 2.2.2
1260 | resolution: "is-error@npm:2.2.2"
1261 | checksum: a97b39587150f0d38f9f93f64699807fe3020fe5edbd63548f234dc2ba96fd7c776d66c062bf031dfeb93c7f48db563ff6bde588418ca041da37c659a416f055
1262 | languageName: node
1263 | linkType: hard
1264 |
1265 | "is-extglob@npm:^2.1.1":
1266 | version: 2.1.1
1267 | resolution: "is-extglob@npm:2.1.1"
1268 | checksum: df033653d06d0eb567461e58a7a8c9f940bd8c22274b94bf7671ab36df5719791aae15eef6d83bbb5e23283967f2f984b8914559d4449efda578c775c4be6f85
1269 | languageName: node
1270 | linkType: hard
1271 |
1272 | "is-fullwidth-code-point@npm:^3.0.0":
1273 | version: 3.0.0
1274 | resolution: "is-fullwidth-code-point@npm:3.0.0"
1275 | checksum: 44a30c29457c7fb8f00297bce733f0a64cd22eca270f83e58c105e0d015e45c019491a4ab2faef91ab51d4738c670daff901c799f6a700e27f7314029e99e348
1276 | languageName: node
1277 | linkType: hard
1278 |
1279 | "is-fullwidth-code-point@npm:^4.0.0":
1280 | version: 4.0.0
1281 | resolution: "is-fullwidth-code-point@npm:4.0.0"
1282 | checksum: 8ae89bf5057bdf4f57b346fb6c55e9c3dd2549983d54191d722d5c739397a903012cc41a04ee3403fd872e811243ef91a7c5196da7b5841dc6b6aae31a264a8d
1283 | languageName: node
1284 | linkType: hard
1285 |
1286 | "is-glob@npm:^4.0.1, is-glob@npm:~4.0.1":
1287 | version: 4.0.3
1288 | resolution: "is-glob@npm:4.0.3"
1289 | dependencies:
1290 | is-extglob: ^2.1.1
1291 | checksum: d381c1319fcb69d341cc6e6c7cd588e17cd94722d9a32dbd60660b993c4fb7d0f19438674e68dfec686d09b7c73139c9166b47597f846af387450224a8101ab4
1292 | languageName: node
1293 | linkType: hard
1294 |
1295 | "is-lambda@npm:^1.0.1":
1296 | version: 1.0.1
1297 | resolution: "is-lambda@npm:1.0.1"
1298 | checksum: 93a32f01940220532e5948538699ad610d5924ac86093fcee83022252b363eb0cc99ba53ab084a04e4fb62bf7b5731f55496257a4c38adf87af9c4d352c71c35
1299 | languageName: node
1300 | linkType: hard
1301 |
1302 | "is-number@npm:^7.0.0":
1303 | version: 7.0.0
1304 | resolution: "is-number@npm:7.0.0"
1305 | checksum: 456ac6f8e0f3111ed34668a624e45315201dff921e5ac181f8ec24923b99e9f32ca1a194912dc79d539c97d33dba17dc635202ff0b2cf98326f608323276d27a
1306 | languageName: node
1307 | linkType: hard
1308 |
1309 | "is-path-cwd@npm:^2.2.0":
1310 | version: 2.2.0
1311 | resolution: "is-path-cwd@npm:2.2.0"
1312 | checksum: 46a840921bb8cc0dc7b5b423a14220e7db338072a4495743a8230533ce78812dc152548c86f4b828411fe98c5451959f07cf841c6a19f611e46600bd699e8048
1313 | languageName: node
1314 | linkType: hard
1315 |
1316 | "is-path-inside@npm:^3.0.2":
1317 | version: 3.0.3
1318 | resolution: "is-path-inside@npm:3.0.3"
1319 | checksum: abd50f06186a052b349c15e55b182326f1936c89a78bf6c8f2b707412517c097ce04bc49a0ca221787bc44e1049f51f09a2ffb63d22899051988d3a618ba13e9
1320 | languageName: node
1321 | linkType: hard
1322 |
1323 | "is-plain-object@npm:^5.0.0":
1324 | version: 5.0.0
1325 | resolution: "is-plain-object@npm:5.0.0"
1326 | checksum: e32d27061eef62c0847d303125440a38660517e586f2f3db7c9d179ae5b6674ab0f469d519b2e25c147a1a3bc87156d0d5f4d8821e0ce4a9ee7fe1fcf11ce45c
1327 | languageName: node
1328 | linkType: hard
1329 |
1330 | "is-promise@npm:^4.0.0":
1331 | version: 4.0.0
1332 | resolution: "is-promise@npm:4.0.0"
1333 | checksum: 0b46517ad47b00b6358fd6553c83ec1f6ba9acd7ffb3d30a0bf519c5c69e7147c132430452351b8a9fc198f8dd6c4f76f8e6f5a7f100f8c77d57d9e0f4261a8a
1334 | languageName: node
1335 | linkType: hard
1336 |
1337 | "is-unicode-supported@npm:^1.2.0":
1338 | version: 1.2.0
1339 | resolution: "is-unicode-supported@npm:1.2.0"
1340 | checksum: 2d90b4b3ce622c1ecf7414b8954cc8f0483576d4d8e6892cbbdc1e2dd33d6126b1cf0319cf1549bee03d45f989b8b0de3309c879a9388a4fe6b8836f866ed86c
1341 | languageName: node
1342 | linkType: hard
1343 |
1344 | "isexe@npm:^2.0.0":
1345 | version: 2.0.0
1346 | resolution: "isexe@npm:2.0.0"
1347 | checksum: 26bf6c5480dda5161c820c5b5c751ae1e766c587b1f951ea3fcfc973bafb7831ae5b54a31a69bd670220e42e99ec154475025a468eae58ea262f813fdc8d1c62
1348 | languageName: node
1349 | linkType: hard
1350 |
1351 | "js-string-escape@npm:^1.0.1":
1352 | version: 1.0.1
1353 | resolution: "js-string-escape@npm:1.0.1"
1354 | checksum: f11e0991bf57e0c183b55c547acec85bd2445f043efc9ea5aa68b41bd2a3e7d3ce94636cb233ae0d84064ba4c1a505d32e969813c5b13f81e7d4be12c59256fe
1355 | languageName: node
1356 | linkType: hard
1357 |
1358 | "js-yaml@npm:^3.14.1":
1359 | version: 3.14.1
1360 | resolution: "js-yaml@npm:3.14.1"
1361 | dependencies:
1362 | argparse: ^1.0.7
1363 | esprima: ^4.0.0
1364 | bin:
1365 | js-yaml: bin/js-yaml.js
1366 | checksum: bef146085f472d44dee30ec34e5cf36bf89164f5d585435a3d3da89e52622dff0b188a580e4ad091c3341889e14cb88cac6e4deb16dc5b1e9623bb0601fc255c
1367 | languageName: node
1368 | linkType: hard
1369 |
1370 | "load-json-file@npm:^7.0.0":
1371 | version: 7.0.1
1372 | resolution: "load-json-file@npm:7.0.1"
1373 | checksum: a560288da6891778321ef993e4bdbdf05374a4f3a3aeedd5ba6b64672798c830d748cfc59a2ec9891a3db30e78b3d04172e0dcb0d4828168289a393147ca0e74
1374 | languageName: node
1375 | linkType: hard
1376 |
1377 | "locate-path@npm:^7.1.0":
1378 | version: 7.1.0
1379 | resolution: "locate-path@npm:7.1.0"
1380 | dependencies:
1381 | p-locate: ^6.0.0
1382 | checksum: 17d5eb6c04ff31856f8a6ae4ee3e3091d41485657428d1a91bd5f66aa1fcd7a90db3de6e8ffb905c2ff1a0014b77509b98dd6410424505efc08b1726d50bcbfc
1383 | languageName: node
1384 | linkType: hard
1385 |
1386 | "lodash@npm:^4.17.15":
1387 | version: 4.17.21
1388 | resolution: "lodash@npm:4.17.21"
1389 | checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7
1390 | languageName: node
1391 | linkType: hard
1392 |
1393 | "lru-cache@npm:^6.0.0":
1394 | version: 6.0.0
1395 | resolution: "lru-cache@npm:6.0.0"
1396 | dependencies:
1397 | yallist: ^4.0.0
1398 | checksum: f97f499f898f23e4585742138a22f22526254fdba6d75d41a1c2526b3b6cc5747ef59c5612ba7375f42aca4f8461950e925ba08c991ead0651b4918b7c978297
1399 | languageName: node
1400 | linkType: hard
1401 |
1402 | "lru-cache@npm:^7.7.1":
1403 | version: 7.8.1
1404 | resolution: "lru-cache@npm:7.8.1"
1405 | checksum: 31ea67388c9774300331d70f4affd5a433869bcf0fae5405f967d19d7b447930b713b0566a2e95362c9082034a8b496f3671ccf8f0c061d8e8048412663f9432
1406 | languageName: node
1407 | linkType: hard
1408 |
1409 | "make-fetch-happen@npm:^10.0.3":
1410 | version: 10.1.2
1411 | resolution: "make-fetch-happen@npm:10.1.2"
1412 | dependencies:
1413 | agentkeepalive: ^4.2.1
1414 | cacache: ^16.0.2
1415 | http-cache-semantics: ^4.1.0
1416 | http-proxy-agent: ^5.0.0
1417 | https-proxy-agent: ^5.0.0
1418 | is-lambda: ^1.0.1
1419 | lru-cache: ^7.7.1
1420 | minipass: ^3.1.6
1421 | minipass-collect: ^1.0.2
1422 | minipass-fetch: ^2.0.3
1423 | minipass-flush: ^1.0.5
1424 | minipass-pipeline: ^1.2.4
1425 | negotiator: ^0.6.3
1426 | promise-retry: ^2.0.1
1427 | socks-proxy-agent: ^6.1.1
1428 | ssri: ^9.0.0
1429 | checksum: 42825d119a7e4f5b1a8e7048a86d328cd36bb1ff875d155ce7079d9a0afdd310c198fb310096af358cfa9ecdf643cecf960380686792457dccb36e17efe89eb0
1430 | languageName: node
1431 | linkType: hard
1432 |
1433 | "map-age-cleaner@npm:^0.1.3":
1434 | version: 0.1.3
1435 | resolution: "map-age-cleaner@npm:0.1.3"
1436 | dependencies:
1437 | p-defer: ^1.0.0
1438 | checksum: cb2804a5bcb3cbdfe4b59066ea6d19f5e7c8c196cd55795ea4c28f792b192e4c442426ae52524e5e1acbccf393d3bddacefc3d41f803e66453f6c4eda3650bc1
1439 | languageName: node
1440 | linkType: hard
1441 |
1442 | "matcher@npm:^5.0.0":
1443 | version: 5.0.0
1444 | resolution: "matcher@npm:5.0.0"
1445 | dependencies:
1446 | escape-string-regexp: ^5.0.0
1447 | checksum: 28f191c2d23fee0f6f32fd0181d9fe173b0ab815a919edba55605438a2f9fa40372e002574a1b17add981b0a8669c75bc6194318d065ed2dceffd8b160c38118
1448 | languageName: node
1449 | linkType: hard
1450 |
1451 | "md5-hex@npm:^3.0.1":
1452 | version: 3.0.1
1453 | resolution: "md5-hex@npm:3.0.1"
1454 | dependencies:
1455 | blueimp-md5: ^2.10.0
1456 | checksum: 6799a19e8bdd3e0c2861b94c1d4d858a89220488d7885c1fa236797e367d0c2e5f2b789e05309307083503f85be3603a9686a5915568a473137d6b4117419cc2
1457 | languageName: node
1458 | linkType: hard
1459 |
1460 | "mem@npm:^9.0.2":
1461 | version: 9.0.2
1462 | resolution: "mem@npm:9.0.2"
1463 | dependencies:
1464 | map-age-cleaner: ^0.1.3
1465 | mimic-fn: ^4.0.0
1466 | checksum: 07829bb182af0e3ecf748dc2edb1c3b10a256ef10458f7e24d06561a2adc2b3ef34d14abe81678bbcedb46faa477e7370223f118b1a5e1252da5fe43496f3967
1467 | languageName: node
1468 | linkType: hard
1469 |
1470 | "merge2@npm:^1.3.0, merge2@npm:^1.4.1":
1471 | version: 1.4.1
1472 | resolution: "merge2@npm:1.4.1"
1473 | checksum: 7268db63ed5169466540b6fb947aec313200bcf6d40c5ab722c22e242f651994619bcd85601602972d3c85bd2cc45a358a4c61937e9f11a061919a1da569b0c2
1474 | languageName: node
1475 | linkType: hard
1476 |
1477 | "micromatch@npm:^4.0.4":
1478 | version: 4.0.5
1479 | resolution: "micromatch@npm:4.0.5"
1480 | dependencies:
1481 | braces: ^3.0.2
1482 | picomatch: ^2.3.1
1483 | checksum: 02a17b671c06e8fefeeb6ef996119c1e597c942e632a21ef589154f23898c9c6a9858526246abb14f8bca6e77734aa9dcf65476fca47cedfb80d9577d52843fc
1484 | languageName: node
1485 | linkType: hard
1486 |
1487 | "mimic-fn@npm:^4.0.0":
1488 | version: 4.0.0
1489 | resolution: "mimic-fn@npm:4.0.0"
1490 | checksum: 995dcece15ee29aa16e188de6633d43a3db4611bcf93620e7e62109ec41c79c0f34277165b8ce5e361205049766e371851264c21ac64ca35499acb5421c2ba56
1491 | languageName: node
1492 | linkType: hard
1493 |
1494 | "minimatch@npm:^3.0.4":
1495 | version: 3.1.2
1496 | resolution: "minimatch@npm:3.1.2"
1497 | dependencies:
1498 | brace-expansion: ^1.1.7
1499 | checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a
1500 | languageName: node
1501 | linkType: hard
1502 |
1503 | "minimatch@npm:^5.0.1":
1504 | version: 5.0.1
1505 | resolution: "minimatch@npm:5.0.1"
1506 | dependencies:
1507 | brace-expansion: ^2.0.1
1508 | checksum: b34b98463da4754bc526b244d680c69d4d6089451ebe512edaf6dd9eeed0279399cfa3edb19233513b8f830bf4bfcad911dddcdf125e75074100d52f724774f0
1509 | languageName: node
1510 | linkType: hard
1511 |
1512 | "minipass-collect@npm:^1.0.2":
1513 | version: 1.0.2
1514 | resolution: "minipass-collect@npm:1.0.2"
1515 | dependencies:
1516 | minipass: ^3.0.0
1517 | checksum: 14df761028f3e47293aee72888f2657695ec66bd7d09cae7ad558da30415fdc4752bbfee66287dcc6fd5e6a2fa3466d6c484dc1cbd986525d9393b9523d97f10
1518 | languageName: node
1519 | linkType: hard
1520 |
1521 | "minipass-fetch@npm:^2.0.3":
1522 | version: 2.1.0
1523 | resolution: "minipass-fetch@npm:2.1.0"
1524 | dependencies:
1525 | encoding: ^0.1.13
1526 | minipass: ^3.1.6
1527 | minipass-sized: ^1.0.3
1528 | minizlib: ^2.1.2
1529 | dependenciesMeta:
1530 | encoding:
1531 | optional: true
1532 | checksum: 1334732859a3f7959ed22589bafd9c40384b885aebb5932328071c33f86b3eb181d54c86919675d1825ab5f1c8e4f328878c863873258d113c29d79a4b0c9c9f
1533 | languageName: node
1534 | linkType: hard
1535 |
1536 | "minipass-flush@npm:^1.0.5":
1537 | version: 1.0.5
1538 | resolution: "minipass-flush@npm:1.0.5"
1539 | dependencies:
1540 | minipass: ^3.0.0
1541 | checksum: 56269a0b22bad756a08a94b1ffc36b7c9c5de0735a4dd1ab2b06c066d795cfd1f0ac44a0fcae13eece5589b908ecddc867f04c745c7009be0b566421ea0944cf
1542 | languageName: node
1543 | linkType: hard
1544 |
1545 | "minipass-pipeline@npm:^1.2.4":
1546 | version: 1.2.4
1547 | resolution: "minipass-pipeline@npm:1.2.4"
1548 | dependencies:
1549 | minipass: ^3.0.0
1550 | checksum: b14240dac0d29823c3d5911c286069e36d0b81173d7bdf07a7e4a91ecdef92cdff4baaf31ea3746f1c61e0957f652e641223970870e2353593f382112257971b
1551 | languageName: node
1552 | linkType: hard
1553 |
1554 | "minipass-sized@npm:^1.0.3":
1555 | version: 1.0.3
1556 | resolution: "minipass-sized@npm:1.0.3"
1557 | dependencies:
1558 | minipass: ^3.0.0
1559 | checksum: 79076749fcacf21b5d16dd596d32c3b6bf4d6e62abb43868fac21674078505c8b15eaca4e47ed844985a4514854f917d78f588fcd029693709417d8f98b2bd60
1560 | languageName: node
1561 | linkType: hard
1562 |
1563 | "minipass@npm:^3.0.0, minipass@npm:^3.1.1, minipass@npm:^3.1.6":
1564 | version: 3.1.6
1565 | resolution: "minipass@npm:3.1.6"
1566 | dependencies:
1567 | yallist: ^4.0.0
1568 | checksum: 57a04041413a3531a65062452cb5175f93383ef245d6f4a2961d34386eb9aa8ac11ac7f16f791f5e8bbaf1dfb1ef01596870c88e8822215db57aa591a5bb0a77
1569 | languageName: node
1570 | linkType: hard
1571 |
1572 | "minizlib@npm:^2.1.1, minizlib@npm:^2.1.2":
1573 | version: 2.1.2
1574 | resolution: "minizlib@npm:2.1.2"
1575 | dependencies:
1576 | minipass: ^3.0.0
1577 | yallist: ^4.0.0
1578 | checksum: f1fdeac0b07cf8f30fcf12f4b586795b97be856edea22b5e9072707be51fc95d41487faec3f265b42973a304fe3a64acd91a44a3826a963e37b37bafde0212c3
1579 | languageName: node
1580 | linkType: hard
1581 |
1582 | "mkdirp@npm:^1.0.3, mkdirp@npm:^1.0.4":
1583 | version: 1.0.4
1584 | resolution: "mkdirp@npm:1.0.4"
1585 | bin:
1586 | mkdirp: bin/cmd.js
1587 | checksum: a96865108c6c3b1b8e1d5e9f11843de1e077e57737602de1b82030815f311be11f96f09cce59bd5b903d0b29834733e5313f9301e3ed6d6f6fba2eae0df4298f
1588 | languageName: node
1589 | linkType: hard
1590 |
1591 | "ms@npm:2.1.2":
1592 | version: 2.1.2
1593 | resolution: "ms@npm:2.1.2"
1594 | checksum: 673cdb2c3133eb050c745908d8ce632ed2c02d85640e2edb3ace856a2266a813b30c613569bf3354fdf4ea7d1a1494add3bfa95e2713baa27d0c2c71fc44f58f
1595 | languageName: node
1596 | linkType: hard
1597 |
1598 | "ms@npm:^2.0.0, ms@npm:^2.1.3":
1599 | version: 2.1.3
1600 | resolution: "ms@npm:2.1.3"
1601 | checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d
1602 | languageName: node
1603 | linkType: hard
1604 |
1605 | "negotiator@npm:^0.6.3":
1606 | version: 0.6.3
1607 | resolution: "negotiator@npm:0.6.3"
1608 | checksum: b8ffeb1e262eff7968fc90a2b6767b04cfd9842582a9d0ece0af7049537266e7b2506dfb1d107a32f06dd849ab2aea834d5830f7f4d0e5cb7d36e1ae55d021d9
1609 | languageName: node
1610 | linkType: hard
1611 |
1612 | "node-gyp@npm:latest":
1613 | version: 9.0.0
1614 | resolution: "node-gyp@npm:9.0.0"
1615 | dependencies:
1616 | env-paths: ^2.2.0
1617 | glob: ^7.1.4
1618 | graceful-fs: ^4.2.6
1619 | make-fetch-happen: ^10.0.3
1620 | nopt: ^5.0.0
1621 | npmlog: ^6.0.0
1622 | rimraf: ^3.0.2
1623 | semver: ^7.3.5
1624 | tar: ^6.1.2
1625 | which: ^2.0.2
1626 | bin:
1627 | node-gyp: bin/node-gyp.js
1628 | checksum: 4d8ef8860f7e4f4d86c91db3f519d26ed5cc23b48fe54543e2afd86162b4acbd14f21de42a5db344525efb69a991e021b96a68c70c6e2d5f4a5cb770793da6d3
1629 | languageName: node
1630 | linkType: hard
1631 |
1632 | "nofilter@npm:^3.1.0":
1633 | version: 3.1.0
1634 | resolution: "nofilter@npm:3.1.0"
1635 | checksum: 58aa85a5b4b35cbb6e42de8a8591c5e338061edc9f3e7286f2c335e9e9b9b8fa7c335ae45daa8a1f3433164dc0b9a3d187fa96f9516e04a17a1f9ce722becc4f
1636 | languageName: node
1637 | linkType: hard
1638 |
1639 | "nopt@npm:^5.0.0":
1640 | version: 5.0.0
1641 | resolution: "nopt@npm:5.0.0"
1642 | dependencies:
1643 | abbrev: 1
1644 | bin:
1645 | nopt: bin/nopt.js
1646 | checksum: d35fdec187269503843924e0114c0c6533fb54bbf1620d0f28b4b60ba01712d6687f62565c55cc20a504eff0fbe5c63e22340c3fad549ad40469ffb611b04f2f
1647 | languageName: node
1648 | linkType: hard
1649 |
1650 | "normalize-path@npm:^3.0.0, normalize-path@npm:~3.0.0":
1651 | version: 3.0.0
1652 | resolution: "normalize-path@npm:3.0.0"
1653 | checksum: 88eeb4da891e10b1318c4b2476b6e2ecbeb5ff97d946815ffea7794c31a89017c70d7f34b3c2ebf23ef4e9fc9fb99f7dffe36da22011b5b5c6ffa34f4873ec20
1654 | languageName: node
1655 | linkType: hard
1656 |
1657 | "npmlog@npm:^6.0.0":
1658 | version: 6.0.2
1659 | resolution: "npmlog@npm:6.0.2"
1660 | dependencies:
1661 | are-we-there-yet: ^3.0.0
1662 | console-control-strings: ^1.1.0
1663 | gauge: ^4.0.3
1664 | set-blocking: ^2.0.0
1665 | checksum: ae238cd264a1c3f22091cdd9e2b106f684297d3c184f1146984ecbe18aaa86343953f26b9520dedd1b1372bc0316905b736c1932d778dbeb1fcf5a1001390e2a
1666 | languageName: node
1667 | linkType: hard
1668 |
1669 | "once@npm:^1.3.0":
1670 | version: 1.4.0
1671 | resolution: "once@npm:1.4.0"
1672 | dependencies:
1673 | wrappy: 1
1674 | checksum: cd0a88501333edd640d95f0d2700fbde6bff20b3d4d9bdc521bdd31af0656b5706570d6c6afe532045a20bb8dc0849f8332d6f2a416e0ba6d3d3b98806c7db68
1675 | languageName: node
1676 | linkType: hard
1677 |
1678 | "p-defer@npm:^1.0.0":
1679 | version: 1.0.0
1680 | resolution: "p-defer@npm:1.0.0"
1681 | checksum: 4271b935c27987e7b6f229e5de4cdd335d808465604644cb7b4c4c95bef266735859a93b16415af8a41fd663ee9e3b97a1a2023ca9def613dba1bad2a0da0c7b
1682 | languageName: node
1683 | linkType: hard
1684 |
1685 | "p-event@npm:^5.0.1":
1686 | version: 5.0.1
1687 | resolution: "p-event@npm:5.0.1"
1688 | dependencies:
1689 | p-timeout: ^5.0.2
1690 | checksum: 3bdd8df6092e6b149f25e9c2eb1c0843b3b4279b07be2a2c72c02b65b267a8908c2040fefd606f2497b0f2bcefcd214f8ca5a74f0c883515d400ccf1d88d5683
1691 | languageName: node
1692 | linkType: hard
1693 |
1694 | "p-limit@npm:^4.0.0":
1695 | version: 4.0.0
1696 | resolution: "p-limit@npm:4.0.0"
1697 | dependencies:
1698 | yocto-queue: ^1.0.0
1699 | checksum: 01d9d70695187788f984226e16c903475ec6a947ee7b21948d6f597bed788e3112cc7ec2e171c1d37125057a5f45f3da21d8653e04a3a793589e12e9e80e756b
1700 | languageName: node
1701 | linkType: hard
1702 |
1703 | "p-locate@npm:^6.0.0":
1704 | version: 6.0.0
1705 | resolution: "p-locate@npm:6.0.0"
1706 | dependencies:
1707 | p-limit: ^4.0.0
1708 | checksum: 2bfe5234efa5e7a4e74b30a5479a193fdd9236f8f6b4d2f3f69e3d286d9a7d7ab0c118a2a50142efcf4e41625def635bd9332d6cbf9cc65d85eb0718c579ab38
1709 | languageName: node
1710 | linkType: hard
1711 |
1712 | "p-map@npm:^4.0.0":
1713 | version: 4.0.0
1714 | resolution: "p-map@npm:4.0.0"
1715 | dependencies:
1716 | aggregate-error: ^3.0.0
1717 | checksum: cb0ab21ec0f32ddffd31dfc250e3afa61e103ef43d957cc45497afe37513634589316de4eb88abdfd969fe6410c22c0b93ab24328833b8eb1ccc087fc0442a1c
1718 | languageName: node
1719 | linkType: hard
1720 |
1721 | "p-map@npm:^5.3.0":
1722 | version: 5.3.0
1723 | resolution: "p-map@npm:5.3.0"
1724 | dependencies:
1725 | aggregate-error: ^4.0.0
1726 | checksum: 744f47b110a8a4c0a302fcae901abcf4224f269239d14f5f1eb2bf790a96e68146ad1acba0b57d8aeff013d17b2145324d9b56c601284db324fa13816ee155ec
1727 | languageName: node
1728 | linkType: hard
1729 |
1730 | "p-timeout@npm:^5.0.2":
1731 | version: 5.0.2
1732 | resolution: "p-timeout@npm:5.0.2"
1733 | checksum: 69eda717e2cbc3d831617a805e069ce69f8cbf51b70f1d1760d3d118536c6b891bbc74f758a4e0d337180ff053f65cdbfc9f5dd04f368ab38173e76f47cf13a8
1734 | languageName: node
1735 | linkType: hard
1736 |
1737 | "parse-ms@npm:^2.1.0":
1738 | version: 2.1.0
1739 | resolution: "parse-ms@npm:2.1.0"
1740 | checksum: d5c66c76cca8df5bd0574e2d11b9c3752893b59b466e74308d4a2f09760dc5436a1633f549cad300fc8c3c19154d14959a3b8333d3b2f7bd75898fe18149d564
1741 | languageName: node
1742 | linkType: hard
1743 |
1744 | "path-exists@npm:^5.0.0":
1745 | version: 5.0.0
1746 | resolution: "path-exists@npm:5.0.0"
1747 | checksum: 8ca842868cab09423994596eb2c5ec2a971c17d1a3cb36dbf060592c730c725cd524b9067d7d2a1e031fef9ba7bd2ac6dc5ec9fb92aa693265f7be3987045254
1748 | languageName: node
1749 | linkType: hard
1750 |
1751 | "path-is-absolute@npm:^1.0.0":
1752 | version: 1.0.1
1753 | resolution: "path-is-absolute@npm:1.0.1"
1754 | checksum: 060840f92cf8effa293bcc1bea81281bd7d363731d214cbe5c227df207c34cd727430f70c6037b5159c8a870b9157cba65e775446b0ab06fd5ecc7e54615a3b8
1755 | languageName: node
1756 | linkType: hard
1757 |
1758 | "path-type@npm:^4.0.0":
1759 | version: 4.0.0
1760 | resolution: "path-type@npm:4.0.0"
1761 | checksum: 5b1e2daa247062061325b8fdbfd1fb56dde0a448fb1455453276ea18c60685bdad23a445dc148cf87bc216be1573357509b7d4060494a6fd768c7efad833ee45
1762 | languageName: node
1763 | linkType: hard
1764 |
1765 | "picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.3.1":
1766 | version: 2.3.1
1767 | resolution: "picomatch@npm:2.3.1"
1768 | checksum: 050c865ce81119c4822c45d3c84f1ced46f93a0126febae20737bd05ca20589c564d6e9226977df859ed5e03dc73f02584a2b0faad36e896936238238b0446cf
1769 | languageName: node
1770 | linkType: hard
1771 |
1772 | "pkg-conf@npm:^4.0.0":
1773 | version: 4.0.0
1774 | resolution: "pkg-conf@npm:4.0.0"
1775 | dependencies:
1776 | find-up: ^6.0.0
1777 | load-json-file: ^7.0.0
1778 | checksum: 6da0c064a74f6c7ae80d7d68c5853e14f7e762a2a80c6ca9e0aa827002b90b69c86fefe3bac830b10a6f1739e7f96a1f728637f2a141e50b0fdafe92a2c3eab6
1779 | languageName: node
1780 | linkType: hard
1781 |
1782 | "plur@npm:^5.1.0":
1783 | version: 5.1.0
1784 | resolution: "plur@npm:5.1.0"
1785 | dependencies:
1786 | irregular-plurals: ^3.3.0
1787 | checksum: 57e400dc4b926768fb0abab7f8688fe17e85673712134546e7beaaee188bae7e0504976e847d7e41d0d6103ff2fd61204095f03c2a45de19a8bad15aecb45cc1
1788 | languageName: node
1789 | linkType: hard
1790 |
1791 | "pretty-ms@npm:^7.0.1":
1792 | version: 7.0.1
1793 | resolution: "pretty-ms@npm:7.0.1"
1794 | dependencies:
1795 | parse-ms: ^2.1.0
1796 | checksum: d76c4920283b48be91f1d3797a2ce4bd51187d58d2a609ae993c028f73c92d16439449d857af57ccad91ae3a38b30c87307f5589749a056102ebb494c686957e
1797 | languageName: node
1798 | linkType: hard
1799 |
1800 | "promise-inflight@npm:^1.0.1":
1801 | version: 1.0.1
1802 | resolution: "promise-inflight@npm:1.0.1"
1803 | checksum: 22749483091d2c594261517f4f80e05226d4d5ecc1fc917e1886929da56e22b5718b7f2a75f3807e7a7d471bc3be2907fe92e6e8f373ddf5c64bae35b5af3981
1804 | languageName: node
1805 | linkType: hard
1806 |
1807 | "promise-retry@npm:^2.0.1":
1808 | version: 2.0.1
1809 | resolution: "promise-retry@npm:2.0.1"
1810 | dependencies:
1811 | err-code: ^2.0.2
1812 | retry: ^0.12.0
1813 | checksum: f96a3f6d90b92b568a26f71e966cbbc0f63ab85ea6ff6c81284dc869b41510e6cdef99b6b65f9030f0db422bf7c96652a3fff9f2e8fb4a0f069d8f4430359429
1814 | languageName: node
1815 | linkType: hard
1816 |
1817 | "queue-microtask@npm:^1.2.2":
1818 | version: 1.2.3
1819 | resolution: "queue-microtask@npm:1.2.3"
1820 | checksum: b676f8c040cdc5b12723ad2f91414d267605b26419d5c821ff03befa817ddd10e238d22b25d604920340fd73efd8ba795465a0377c4adf45a4a41e4234e42dc4
1821 | languageName: node
1822 | linkType: hard
1823 |
1824 | "readable-stream@npm:^3.6.0":
1825 | version: 3.6.0
1826 | resolution: "readable-stream@npm:3.6.0"
1827 | dependencies:
1828 | inherits: ^2.0.3
1829 | string_decoder: ^1.1.1
1830 | util-deprecate: ^1.0.1
1831 | checksum: d4ea81502d3799439bb955a3a5d1d808592cf3133350ed352aeaa499647858b27b1c4013984900238b0873ec8d0d8defce72469fb7a83e61d53f5ad61cb80dc8
1832 | languageName: node
1833 | linkType: hard
1834 |
1835 | "readdirp@npm:~3.6.0":
1836 | version: 3.6.0
1837 | resolution: "readdirp@npm:3.6.0"
1838 | dependencies:
1839 | picomatch: ^2.2.1
1840 | checksum: 1ced032e6e45670b6d7352d71d21ce7edf7b9b928494dcaba6f11fba63180d9da6cd7061ebc34175ffda6ff529f481818c962952004d273178acd70f7059b320
1841 | languageName: node
1842 | linkType: hard
1843 |
1844 | "require-directory@npm:^2.1.1":
1845 | version: 2.1.1
1846 | resolution: "require-directory@npm:2.1.1"
1847 | checksum: fb47e70bf0001fdeabdc0429d431863e9475e7e43ea5f94ad86503d918423c1543361cc5166d713eaa7029dd7a3d34775af04764bebff99ef413111a5af18c80
1848 | languageName: node
1849 | linkType: hard
1850 |
1851 | "resolve-cwd@npm:^3.0.0":
1852 | version: 3.0.0
1853 | resolution: "resolve-cwd@npm:3.0.0"
1854 | dependencies:
1855 | resolve-from: ^5.0.0
1856 | checksum: 546e0816012d65778e580ad62b29e975a642989108d9a3c5beabfb2304192fa3c9f9146fbdfe213563c6ff51975ae41bac1d3c6e047dd9572c94863a057b4d81
1857 | languageName: node
1858 | linkType: hard
1859 |
1860 | "resolve-from@npm:^5.0.0":
1861 | version: 5.0.0
1862 | resolution: "resolve-from@npm:5.0.0"
1863 | checksum: 4ceeb9113e1b1372d0cd969f3468fa042daa1dd9527b1b6bb88acb6ab55d8b9cd65dbf18819f9f9ddf0db804990901dcdaade80a215e7b2c23daae38e64f5bdf
1864 | languageName: node
1865 | linkType: hard
1866 |
1867 | "retry@npm:^0.12.0":
1868 | version: 0.12.0
1869 | resolution: "retry@npm:0.12.0"
1870 | checksum: 623bd7d2e5119467ba66202d733ec3c2e2e26568074923bc0585b6b99db14f357e79bdedb63cab56cec47491c4a0da7e6021a7465ca6dc4f481d3898fdd3158c
1871 | languageName: node
1872 | linkType: hard
1873 |
1874 | "reusify@npm:^1.0.4":
1875 | version: 1.0.4
1876 | resolution: "reusify@npm:1.0.4"
1877 | checksum: c3076ebcc22a6bc252cb0b9c77561795256c22b757f40c0d8110b1300723f15ec0fc8685e8d4ea6d7666f36c79ccc793b1939c748bf36f18f542744a4e379fcc
1878 | languageName: node
1879 | linkType: hard
1880 |
1881 | "rimraf@npm:^3.0.2":
1882 | version: 3.0.2
1883 | resolution: "rimraf@npm:3.0.2"
1884 | dependencies:
1885 | glob: ^7.1.3
1886 | bin:
1887 | rimraf: bin.js
1888 | checksum: 87f4164e396f0171b0a3386cc1877a817f572148ee13a7e113b238e48e8a9f2f31d009a92ec38a591ff1567d9662c6b67fd8818a2dbbaed74bc26a87a2a4a9a0
1889 | languageName: node
1890 | linkType: hard
1891 |
1892 | "run-parallel@npm:^1.1.9":
1893 | version: 1.2.0
1894 | resolution: "run-parallel@npm:1.2.0"
1895 | dependencies:
1896 | queue-microtask: ^1.2.2
1897 | checksum: cb4f97ad25a75ebc11a8ef4e33bb962f8af8516bb2001082ceabd8902e15b98f4b84b4f8a9b222e5d57fc3bd1379c483886ed4619367a7680dad65316993021d
1898 | languageName: node
1899 | linkType: hard
1900 |
1901 | "safe-buffer@npm:~5.2.0":
1902 | version: 5.2.1
1903 | resolution: "safe-buffer@npm:5.2.1"
1904 | checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491
1905 | languageName: node
1906 | linkType: hard
1907 |
1908 | "safer-buffer@npm:>= 2.1.2 < 3.0.0":
1909 | version: 2.1.2
1910 | resolution: "safer-buffer@npm:2.1.2"
1911 | checksum: cab8f25ae6f1434abee8d80023d7e72b598cf1327164ddab31003c51215526801e40b66c5e65d658a0af1e9d6478cadcb4c745f4bd6751f97d8644786c0978b0
1912 | languageName: node
1913 | linkType: hard
1914 |
1915 | "semver@npm:^7.3.2, semver@npm:^7.3.5":
1916 | version: 7.3.7
1917 | resolution: "semver@npm:7.3.7"
1918 | dependencies:
1919 | lru-cache: ^6.0.0
1920 | bin:
1921 | semver: bin/semver.js
1922 | checksum: 2fa3e877568cd6ce769c75c211beaed1f9fce80b28338cadd9d0b6c40f2e2862bafd62c19a6cff42f3d54292b7c623277bcab8816a2b5521cf15210d43e75232
1923 | languageName: node
1924 | linkType: hard
1925 |
1926 | "serialize-error@npm:^7.0.1":
1927 | version: 7.0.1
1928 | resolution: "serialize-error@npm:7.0.1"
1929 | dependencies:
1930 | type-fest: ^0.13.1
1931 | checksum: e0aba4dca2fc9fe74ae1baf38dbd99190e1945445a241ba646290f2176cdb2032281a76443b02ccf0caf30da5657d510746506368889a593b9835a497fc0732e
1932 | languageName: node
1933 | linkType: hard
1934 |
1935 | "set-blocking@npm:^2.0.0":
1936 | version: 2.0.0
1937 | resolution: "set-blocking@npm:2.0.0"
1938 | checksum: 6e65a05f7cf7ebdf8b7c75b101e18c0b7e3dff4940d480efed8aad3a36a4005140b660fa1d804cb8bce911cac290441dc728084a30504d3516ac2ff7ad607b02
1939 | languageName: node
1940 | linkType: hard
1941 |
1942 | "signal-exit@npm:^3.0.7":
1943 | version: 3.0.7
1944 | resolution: "signal-exit@npm:3.0.7"
1945 | checksum: a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318
1946 | languageName: node
1947 | linkType: hard
1948 |
1949 | "slash@npm:^3.0.0":
1950 | version: 3.0.0
1951 | resolution: "slash@npm:3.0.0"
1952 | checksum: 94a93fff615f25a999ad4b83c9d5e257a7280c90a32a7cb8b4a87996e4babf322e469c42b7f649fd5796edd8687652f3fb452a86dc97a816f01113183393f11c
1953 | languageName: node
1954 | linkType: hard
1955 |
1956 | "slash@npm:^4.0.0":
1957 | version: 4.0.0
1958 | resolution: "slash@npm:4.0.0"
1959 | checksum: da8e4af73712253acd21b7853b7e0dbba776b786e82b010a5bfc8b5051a1db38ed8aba8e1e8f400dd2c9f373be91eb1c42b66e91abb407ff42b10feece5e1d2d
1960 | languageName: node
1961 | linkType: hard
1962 |
1963 | "slice-ansi@npm:^5.0.0":
1964 | version: 5.0.0
1965 | resolution: "slice-ansi@npm:5.0.0"
1966 | dependencies:
1967 | ansi-styles: ^6.0.0
1968 | is-fullwidth-code-point: ^4.0.0
1969 | checksum: 7e600a2a55e333a21ef5214b987c8358fe28bfb03c2867ff2cbf919d62143d1812ac27b4297a077fdaf27a03da3678e49551c93e35f9498a3d90221908a1180e
1970 | languageName: node
1971 | linkType: hard
1972 |
1973 | "smart-buffer@npm:^4.2.0":
1974 | version: 4.2.0
1975 | resolution: "smart-buffer@npm:4.2.0"
1976 | checksum: b5167a7142c1da704c0e3af85c402002b597081dd9575031a90b4f229ca5678e9a36e8a374f1814c8156a725d17008ae3bde63b92f9cfd132526379e580bec8b
1977 | languageName: node
1978 | linkType: hard
1979 |
1980 | "socks-proxy-agent@npm:^6.1.1":
1981 | version: 6.2.0
1982 | resolution: "socks-proxy-agent@npm:6.2.0"
1983 | dependencies:
1984 | agent-base: ^6.0.2
1985 | debug: ^4.3.3
1986 | socks: ^2.6.2
1987 | checksum: 6723fd64fb50334e2b340fd0a80fd8488ffc5bc43d85b7cf1d25612044f814dd7d6ea417fd47602159941236f7f4bd15669fa5d7e1f852598a31288e1a43967b
1988 | languageName: node
1989 | linkType: hard
1990 |
1991 | "socks@npm:^2.6.2":
1992 | version: 2.6.2
1993 | resolution: "socks@npm:2.6.2"
1994 | dependencies:
1995 | ip: ^1.1.5
1996 | smart-buffer: ^4.2.0
1997 | checksum: dd9194293059d737759d5c69273850ad4149f448426249325c4bea0e340d1cf3d266c3b022694b0dcf5d31f759de23657244c481fc1e8322add80b7985c36b5e
1998 | languageName: node
1999 | linkType: hard
2000 |
2001 | "sprintf-js@npm:~1.0.2":
2002 | version: 1.0.3
2003 | resolution: "sprintf-js@npm:1.0.3"
2004 | checksum: 19d79aec211f09b99ec3099b5b2ae2f6e9cdefe50bc91ac4c69144b6d3928a640bb6ae5b3def70c2e85a2c3d9f5ec2719921e3a59d3ca3ef4b2fd1a4656a0df3
2005 | languageName: node
2006 | linkType: hard
2007 |
2008 | "ssri@npm:^9.0.0":
2009 | version: 9.0.0
2010 | resolution: "ssri@npm:9.0.0"
2011 | dependencies:
2012 | minipass: ^3.1.1
2013 | checksum: bf33174232d07cc64e77ab1c51b55d28352273380c503d35642a19627e88a2c5f160039bb0a28608a353485075dda084dbf0390c7070f9f284559eb71d01b84b
2014 | languageName: node
2015 | linkType: hard
2016 |
2017 | "stack-utils@npm:^2.0.5":
2018 | version: 2.0.5
2019 | resolution: "stack-utils@npm:2.0.5"
2020 | dependencies:
2021 | escape-string-regexp: ^2.0.0
2022 | checksum: 76b69da0f5b48a34a0f93c98ee2a96544d2c4ca2557f7eef5ddb961d3bdc33870b46f498a84a7c4f4ffb781df639840e7ebf6639164ed4da5e1aeb659615b9c7
2023 | languageName: node
2024 | linkType: hard
2025 |
2026 | "string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3":
2027 | version: 4.2.3
2028 | resolution: "string-width@npm:4.2.3"
2029 | dependencies:
2030 | emoji-regex: ^8.0.0
2031 | is-fullwidth-code-point: ^3.0.0
2032 | strip-ansi: ^6.0.1
2033 | checksum: e52c10dc3fbfcd6c3a15f159f54a90024241d0f149cf8aed2982a2d801d2e64df0bf1dc351cf8e95c3319323f9f220c16e740b06faecd53e2462df1d2b5443fb
2034 | languageName: node
2035 | linkType: hard
2036 |
2037 | "string-width@npm:^5.0.0":
2038 | version: 5.1.2
2039 | resolution: "string-width@npm:5.1.2"
2040 | dependencies:
2041 | eastasianwidth: ^0.2.0
2042 | emoji-regex: ^9.2.2
2043 | strip-ansi: ^7.0.1
2044 | checksum: 7369deaa29f21dda9a438686154b62c2c5f661f8dda60449088f9f980196f7908fc39fdd1803e3e01541970287cf5deae336798337e9319a7055af89dafa7193
2045 | languageName: node
2046 | linkType: hard
2047 |
2048 | "string_decoder@npm:^1.1.1":
2049 | version: 1.3.0
2050 | resolution: "string_decoder@npm:1.3.0"
2051 | dependencies:
2052 | safe-buffer: ~5.2.0
2053 | checksum: 8417646695a66e73aefc4420eb3b84cc9ffd89572861fe004e6aeb13c7bc00e2f616247505d2dbbef24247c372f70268f594af7126f43548565c68c117bdeb56
2054 | languageName: node
2055 | linkType: hard
2056 |
2057 | "strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1":
2058 | version: 6.0.1
2059 | resolution: "strip-ansi@npm:6.0.1"
2060 | dependencies:
2061 | ansi-regex: ^5.0.1
2062 | checksum: f3cd25890aef3ba6e1a74e20896c21a46f482e93df4a06567cebf2b57edabb15133f1f94e57434e0a958d61186087b1008e89c94875d019910a213181a14fc8c
2063 | languageName: node
2064 | linkType: hard
2065 |
2066 | "strip-ansi@npm:^7.0.1":
2067 | version: 7.0.1
2068 | resolution: "strip-ansi@npm:7.0.1"
2069 | dependencies:
2070 | ansi-regex: ^6.0.1
2071 | checksum: 257f78fa433520e7f9897722731d78599cb3fce29ff26a20a5e12ba4957463b50a01136f37c43707f4951817a75e90820174853d6ccc240997adc5df8f966039
2072 | languageName: node
2073 | linkType: hard
2074 |
2075 | "supertap@npm:^3.0.1":
2076 | version: 3.0.1
2077 | resolution: "supertap@npm:3.0.1"
2078 | dependencies:
2079 | indent-string: ^5.0.0
2080 | js-yaml: ^3.14.1
2081 | serialize-error: ^7.0.1
2082 | strip-ansi: ^7.0.1
2083 | checksum: ee3d71c1d25f7f15d4a849e72b0c5f430df7cd8f702cf082fdbec5642a9546be6557766745655fa3a3e9c88f7c7eed849f2d74457b5b72cb9d94a779c0c8a948
2084 | languageName: node
2085 | linkType: hard
2086 |
2087 | "tar@npm:^6.1.11, tar@npm:^6.1.2":
2088 | version: 6.1.11
2089 | resolution: "tar@npm:6.1.11"
2090 | dependencies:
2091 | chownr: ^2.0.0
2092 | fs-minipass: ^2.0.0
2093 | minipass: ^3.0.0
2094 | minizlib: ^2.1.1
2095 | mkdirp: ^1.0.3
2096 | yallist: ^4.0.0
2097 | checksum: a04c07bb9e2d8f46776517d4618f2406fb977a74d914ad98b264fc3db0fe8224da5bec11e5f8902c5b9bcb8ace22d95fbe3c7b36b8593b7dfc8391a25898f32f
2098 | languageName: node
2099 | linkType: hard
2100 |
2101 | "temp-dir@npm:^2.0.0":
2102 | version: 2.0.0
2103 | resolution: "temp-dir@npm:2.0.0"
2104 | checksum: cc4f0404bf8d6ae1a166e0e64f3f409b423f4d1274d8c02814a59a5529f07db6cd070a749664141b992b2c1af337fa9bb451a460a43bb9bcddc49f235d3115aa
2105 | languageName: node
2106 | linkType: hard
2107 |
2108 | "time-zone@npm:^1.0.0":
2109 | version: 1.0.0
2110 | resolution: "time-zone@npm:1.0.0"
2111 | checksum: e46f5a69b8c236dcd8e91e29d40d4e7a3495ed4f59888c3f84ce1d9678e20461421a6ba41233509d47dd94bc18f1a4377764838b21b584663f942b3426dcbce8
2112 | languageName: node
2113 | linkType: hard
2114 |
2115 | "to-regex-range@npm:^5.0.1":
2116 | version: 5.0.1
2117 | resolution: "to-regex-range@npm:5.0.1"
2118 | dependencies:
2119 | is-number: ^7.0.0
2120 | checksum: f76fa01b3d5be85db6a2a143e24df9f60dd047d151062d0ba3df62953f2f697b16fe5dad9b0ac6191c7efc7b1d9dcaa4b768174b7b29da89d4428e64bc0a20ed
2121 | languageName: node
2122 | linkType: hard
2123 |
2124 | "txforge@workspace:.":
2125 | version: 0.0.0-use.local
2126 | resolution: "txforge@workspace:."
2127 | dependencies:
2128 | "@runonbitcoin/nimble": ^1.0.13
2129 | ava: ^4.2.0
2130 | esbuild: ^0.14.38
2131 | esbuild-plugin-globals: ^0.1.1
2132 | languageName: unknown
2133 | linkType: soft
2134 |
2135 | "type-fest@npm:^0.13.1":
2136 | version: 0.13.1
2137 | resolution: "type-fest@npm:0.13.1"
2138 | checksum: e6bf2e3c449f27d4ef5d56faf8b86feafbc3aec3025fc9a5fbe2db0a2587c44714521f9c30d8516a833c8c506d6263f5cc11267522b10c6ccdb6cc55b0a9d1c4
2139 | languageName: node
2140 | linkType: hard
2141 |
2142 | "unique-filename@npm:^1.1.1":
2143 | version: 1.1.1
2144 | resolution: "unique-filename@npm:1.1.1"
2145 | dependencies:
2146 | unique-slug: ^2.0.0
2147 | checksum: cf4998c9228cc7647ba7814e255dec51be43673903897b1786eff2ac2d670f54d4d733357eb08dea969aa5e6875d0e1bd391d668fbdb5a179744e7c7551a6f80
2148 | languageName: node
2149 | linkType: hard
2150 |
2151 | "unique-slug@npm:^2.0.0":
2152 | version: 2.0.2
2153 | resolution: "unique-slug@npm:2.0.2"
2154 | dependencies:
2155 | imurmurhash: ^0.1.4
2156 | checksum: 5b6876a645da08d505dedb970d1571f6cebdf87044cb6b740c8dbb24f0d6e1dc8bdbf46825fd09f994d7cf50760e6f6e063cfa197d51c5902c00a861702eb75a
2157 | languageName: node
2158 | linkType: hard
2159 |
2160 | "util-deprecate@npm:^1.0.1":
2161 | version: 1.0.2
2162 | resolution: "util-deprecate@npm:1.0.2"
2163 | checksum: 474acf1146cb2701fe3b074892217553dfcf9a031280919ba1b8d651a068c9b15d863b7303cb15bd00a862b498e6cf4ad7b4a08fb134edd5a6f7641681cb54a2
2164 | languageName: node
2165 | linkType: hard
2166 |
2167 | "well-known-symbols@npm:^2.0.0":
2168 | version: 2.0.0
2169 | resolution: "well-known-symbols@npm:2.0.0"
2170 | checksum: 4f54bbc3012371cb4d228f436891b8e7536d34ac61a57541890257e96788608e096231e0121ac24d08ef2f908b3eb2dc0adba35023eaeb2a7df655da91415402
2171 | languageName: node
2172 | linkType: hard
2173 |
2174 | "which@npm:^2.0.2":
2175 | version: 2.0.2
2176 | resolution: "which@npm:2.0.2"
2177 | dependencies:
2178 | isexe: ^2.0.0
2179 | bin:
2180 | node-which: ./bin/node-which
2181 | checksum: 1a5c563d3c1b52d5f893c8b61afe11abc3bab4afac492e8da5bde69d550de701cf9806235f20a47b5c8fa8a1d6a9135841de2596535e998027a54589000e66d1
2182 | languageName: node
2183 | linkType: hard
2184 |
2185 | "wide-align@npm:^1.1.5":
2186 | version: 1.1.5
2187 | resolution: "wide-align@npm:1.1.5"
2188 | dependencies:
2189 | string-width: ^1.0.2 || 2 || 3 || 4
2190 | checksum: d5fc37cd561f9daee3c80e03b92ed3e84d80dde3365a8767263d03dacfc8fa06b065ffe1df00d8c2a09f731482fcacae745abfbb478d4af36d0a891fad4834d3
2191 | languageName: node
2192 | linkType: hard
2193 |
2194 | "wrap-ansi@npm:^7.0.0":
2195 | version: 7.0.0
2196 | resolution: "wrap-ansi@npm:7.0.0"
2197 | dependencies:
2198 | ansi-styles: ^4.0.0
2199 | string-width: ^4.1.0
2200 | strip-ansi: ^6.0.0
2201 | checksum: a790b846fd4505de962ba728a21aaeda189b8ee1c7568ca5e817d85930e06ef8d1689d49dbf0e881e8ef84436af3a88bc49115c2e2788d841ff1b8b5b51a608b
2202 | languageName: node
2203 | linkType: hard
2204 |
2205 | "wrappy@npm:1":
2206 | version: 1.0.2
2207 | resolution: "wrappy@npm:1.0.2"
2208 | checksum: 159da4805f7e84a3d003d8841557196034155008f817172d4e986bd591f74aa82aa7db55929a54222309e01079a65a92a9e6414da5a6aa4b01ee44a511ac3ee5
2209 | languageName: node
2210 | linkType: hard
2211 |
2212 | "write-file-atomic@npm:^4.0.1":
2213 | version: 4.0.1
2214 | resolution: "write-file-atomic@npm:4.0.1"
2215 | dependencies:
2216 | imurmurhash: ^0.1.4
2217 | signal-exit: ^3.0.7
2218 | checksum: 8f780232533ca6223c63c9b9c01c4386ca8c625ebe5017a9ed17d037aec19462ae17109e0aa155bff5966ee4ae7a27b67a99f55caf3f32ffd84155e9da3929fc
2219 | languageName: node
2220 | linkType: hard
2221 |
2222 | "y18n@npm:^5.0.5":
2223 | version: 5.0.8
2224 | resolution: "y18n@npm:5.0.8"
2225 | checksum: 54f0fb95621ee60898a38c572c515659e51cc9d9f787fb109cef6fde4befbe1c4602dc999d30110feee37456ad0f1660fa2edcfde6a9a740f86a290999550d30
2226 | languageName: node
2227 | linkType: hard
2228 |
2229 | "yallist@npm:^4.0.0":
2230 | version: 4.0.0
2231 | resolution: "yallist@npm:4.0.0"
2232 | checksum: 343617202af32df2a15a3be36a5a8c0c8545208f3d3dfbc6bb7c3e3b7e8c6f8e7485432e4f3b88da3031a6e20afa7c711eded32ddfb122896ac5d914e75848d5
2233 | languageName: node
2234 | linkType: hard
2235 |
2236 | "yargs-parser@npm:^21.0.0":
2237 | version: 21.0.1
2238 | resolution: "yargs-parser@npm:21.0.1"
2239 | checksum: c3ea2ed12cad0377ce3096b3f138df8267edf7b1aa7d710cd502fe16af417bafe4443dd71b28158c22fcd1be5dfd0e86319597e47badf42ff83815485887323a
2240 | languageName: node
2241 | linkType: hard
2242 |
2243 | "yargs@npm:^17.3.1":
2244 | version: 17.4.1
2245 | resolution: "yargs@npm:17.4.1"
2246 | dependencies:
2247 | cliui: ^7.0.2
2248 | escalade: ^3.1.1
2249 | get-caller-file: ^2.0.5
2250 | require-directory: ^2.1.1
2251 | string-width: ^4.2.3
2252 | y18n: ^5.0.5
2253 | yargs-parser: ^21.0.0
2254 | checksum: e9012322870d7e4e912a6ae1f63b203e365f911c0cf158be92c36edefddfb3bd38ce17eb9ef0d18858a4777f047c50589ea22dacb44bd949169ba37dc6d34bee
2255 | languageName: node
2256 | linkType: hard
2257 |
2258 | "yocto-queue@npm:^1.0.0":
2259 | version: 1.0.0
2260 | resolution: "yocto-queue@npm:1.0.0"
2261 | checksum: 2cac84540f65c64ccc1683c267edce396b26b1e931aa429660aefac8fbe0188167b7aee815a3c22fa59a28a58d898d1a2b1825048f834d8d629f4c2a5d443801
2262 | languageName: node
2263 | linkType: hard
2264 |
--------------------------------------------------------------------------------