diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa15018 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +data \ No newline at end of file diff --git a/README.md b/README.md index b2a2553..f445a1f 100644 --- a/README.md +++ b/README.md @@ -7,4 +7,9 @@ Go to Plugins > Custom Plugin Manager Import this URL: ``` https://git.woodburn.au/nathanwoodburn/firesales-plugin.git -``` \ No newline at end of file +``` + + +npm install shakedex +npm install hsd +node node_modules/shakedex/bin/shakedex transfer-lock coolcode -n main -w hot -a y5cSK42tgVCdt4E58jkHjI3nQ9GU32bC -p ./data \ No newline at end of file diff --git a/firesales.py b/firesales.py index 9a98354..5940f4a 100644 --- a/firesales.py +++ b/firesales.py @@ -1,6 +1,10 @@ import json import account import requests +import os +import subprocess + +path = os.path.realpath("customPlugins/firesales-plugin") # Plugin Data info = { @@ -12,6 +16,18 @@ info = { # Functions functions = { + "init": { + "name": "Init", + "description": "Install prerequisites for atomic swaps", + "type":"default", + "params": {}, + "returns": { + "status": { + "type": "text", + "name": "Status" + } + } + }, "list": { "name": "List", "description": "List a new domain", @@ -60,6 +76,36 @@ functions = { } } +def init(params, authentication): + # Install npm packages + if not os.path.exists(f'{path}/node_modules'): + try: + result = subprocess.run(["npm", "install", ], capture_output=True, text=True, cwd=path) + if result.returncode != 0: + return {"status": "Error: " + result.stderr} + except: + return {"status": "Error: Failed to install npm packages"} + + # Install js patch files + # Copy shakedex/main.js to node_modules/shakedex/src/cli/main.js + try: + result = subprocess.run(["cp", f'{path}/shakedex/main.js', f'{path}/node_modules/shakedex/src/cli/main.js'], capture_output=True, text=True, cwd=path) + if result.returncode != 0: + return {"status": "Error: " + result.stderr} + except: + return {"status": "Error: Failed to install js patch files"} + + # Copy shakedex/index.js to node_modules/shakedex/src/index.js + try: + result = subprocess.run(["cp", f'{path}/shakedex/context.js', f'{path}/node_modules/shakedex/src/context.js'], capture_output=True, text=True, cwd=path) + if result.returncode != 0: + return {"status": "Error: " + result.stderr} + except: + return {"status": "Error: Failed to install js patch files"} + + return {"status": "Success"} + + def list(params, authentication): domain = params["domain"] price = params["price"] diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..32ca9d3 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1602 @@ +{ + "name": "firesales-plugin", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "firesales-plugin", + "version": "1.0.0", + "license": "AGPL-3.0-only", + "dependencies": { + "hsd": "^7.0.1", + "shakedex": "^0.0.19" + } + }, + "node_modules/@handshake-org/bfilter": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@handshake-org/bfilter/-/bfilter-2.3.0.tgz", + "integrity": "sha512-vTKTVJvLHz2knpdnYMT0idb6R+HlOCbYKlw2L9Bk9oKOAXwjOIFUp6hnZKIVb87rYW8eEfUROrFG3+DcYwxm7w==", + "license": "MIT", + "dependencies": { + "bcrypto": "~5.4.0", + "bsert": "~0.0.12", + "bufio": "~1.2.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@handshake-org/bfilter/node_modules/bufio": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bufio/-/bufio-1.2.3.tgz", + "integrity": "sha512-5Tt66bRzYUSlVZatc0E92uDenreJ+DpTBmSAUwL4VSxJn3e6cUyYwx+PoqML0GRZatgA/VX8ybhxItF8InZgqA==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/abstract-leveldown": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz", + "integrity": "sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ==", + "deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "immediate": "^3.2.3", + "level-concat-iterator": "~2.0.0", + "level-supports": "~1.0.0", + "xtend": "~4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "license": "MIT", + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bcfg": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/bcfg/-/bcfg-0.2.2.tgz", + "integrity": "sha512-xa7hYK8ZgEV/Wjh+EJiKLLd+h8A0HGyhyntNMvKCeXIGepLqKUL3KYOE5zFz8EBv8sS3XruD5YPmYIjtwFOrZA==", + "license": "MIT", + "dependencies": { + "bsert": "~0.0.12" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/bcrypto": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/bcrypto/-/bcrypto-5.4.0.tgz", + "integrity": "sha512-KDX2CR29o6ZoqpQndcCxFZAtYA1jDMnXU3jmCfzP44g++Cu7AHHtZN/JbrN/MXAg9SLvtQ8XISG+eVD9zH1+Jg==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "bufio": "~1.0.7", + "loady": "~0.0.5" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/bcurl": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/bcurl/-/bcurl-0.1.10.tgz", + "integrity": "sha512-NPxrIkc61tI2FvuibKW8IHaWs7YpgGvOWTgYEJYoE0vOiCvjuL6PXeKYq6bZqadeZfQ6v+R74qvj3Siiv+/Pvg==", + "license": "MIT", + "dependencies": { + "brq": "~0.1.8", + "bsert": "~0.0.10", + "bsock": "~0.1.9" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/bdb": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/bdb/-/bdb-1.6.2.tgz", + "integrity": "sha512-3PxLeNKqwdqMjc/Ox5hontemGFt/AXGQsrEHFA0bynISfqhYI8r1qQNtJHEMonD6kcvkejfLA/5ad3n813kmdw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "bsert": "~0.0.13", + "loady": "~0.0.5" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/bdns": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/bdns/-/bdns-0.1.5.tgz", + "integrity": "sha512-LNVkfM7ynlAD0CvPvO9cKxW8YXt1KOCRQZlRsGZWeMyymUWVdHQpZudAzH9chaFAz6HiwAnQxwDemCKDPy6Mag==", + "license": "MIT", + "dependencies": { + "bsert": "~0.0.10" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/bevent": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/bevent/-/bevent-0.1.6.tgz", + "integrity": "sha512-vu1MYZIbZhz8s4/QDuqJ06L8BloELnMJxf/bGfp5ifqNpKpdCvgDw3ymsyzu27JJinDiGvx775V5NnTmWR7tFA==", + "license": "MIT", + "dependencies": { + "bsert": "~0.0.12" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/bfile": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/bfile/-/bfile-0.2.3.tgz", + "integrity": "sha512-BhbmCLqDC+u8rPSeB/I8bRC8luQoUt+wD326CECXYXtE5GyTWL/q/OkNp58aH7XEREguEItvqM18s9vXLvg6fw==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/bheep": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/bheep/-/bheep-0.1.6.tgz", + "integrity": "sha512-u44Xgb0Rr+Y/1chKqiUSY44mpBCglDxnapyfA6mssbJE+C7iyAPY4r8WMPqmdvZPYk7EU3ogbt4pKDItDMU87A==", + "license": "MIT", + "dependencies": { + "bsert": "~0.0.12" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/binet": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/binet/-/binet-0.3.9.tgz", + "integrity": "sha512-htptPuT5YTTRThIQAuWyCo+rIvXwAC+CrUq40ldhKHBPbZoMb76SBkI8NtvLkWussJr+lnR5Mc0rh1dpNBrBPg==", + "license": "MIT", + "dependencies": { + "bs32": "~0.1.7", + "bsert": "~0.0.12" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/blgr": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/blgr/-/blgr-0.2.1.tgz", + "integrity": "sha512-ShNWkj8qxjf0JEwDt1h675Lgx9EV8a2lRWVWtZrptqg/tIrISv0TM7s+NVNXEwyIlQYYIu4lQqjlGRYWUn4g5Q==", + "license": "MIT", + "dependencies": { + "bsert": "~0.0.12" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/blru": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/blru/-/blru-0.1.8.tgz", + "integrity": "sha512-9KsgRzBHx4GOJ48bRy0IZf42+f3nAhgAeeuWX5KBditHVqnCFL0ownd1QRr0aJVot7qlKEUYGPfM/tGHW6A3zw==", + "license": "MIT", + "dependencies": { + "bsert": "~0.0.12" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/blst": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/blst/-/blst-0.1.6.tgz", + "integrity": "sha512-P88SBVTdjKsvltTGXPayu9ACSZ36CNpECE8eZjPg+Mj++EB/VHOFUAnVIZ142NceSWYkVMBKiVENH49YHKHjFg==", + "license": "MIT", + "dependencies": { + "bsert": "~0.0.12" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/bmutex": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/bmutex/-/bmutex-0.1.8.tgz", + "integrity": "sha512-NEI6oawCTA9hobAIubvpooRkq7hp+dBg0hf1KUJ3uV77PrXlUgLXr6D/mr6+sfJ0hx523lDaz/vEcJIbK9S1uw==", + "license": "MIT", + "dependencies": { + "bsert": "~0.0.13" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/bns": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/bns/-/bns-0.15.0.tgz", + "integrity": "sha512-iJWQVE399vQzPfhalFMJGEQ7k5Ot2D6Mz8dkoPeLO8huWAMOiJNJ1tHzOu5j+ZyNNew6ITgG/LsSyaRPxvkXuw==", + "license": "MIT", + "dependencies": { + "bcrypto": "~5.4.0", + "bfile": "~0.2.2", + "bheep": "~0.1.5", + "binet": "~0.3.6", + "bs32": "~0.1.6", + "bsert": "~0.0.10", + "btcp": "~0.1.5", + "budp": "~0.1.6", + "bufio": "~1.0.7" + }, + "bin": { + "bns-keygen": "bin/bns-keygen", + "bns-prove": "bin/bns-prove", + "dig.js": "bin/dig.js", + "dig2json": "bin/dig2json", + "json2dig": "bin/json2dig", + "json2rr": "bin/json2rr", + "json2zone": "bin/json2zone", + "named.js": "bin/named.js", + "rr2json": "bin/rr2json", + "whois.js": "bin/whois.js", + "zone2json": "bin/zone2json" + }, + "engines": { + "node": ">=8.0.0" + }, + "optionalDependencies": { + "unbound": "~0.4.3" + } + }, + "node_modules/brq": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/brq/-/brq-0.1.10.tgz", + "integrity": "sha512-iil4TtQWw9Wb2G+mEP0iHqM8Q16mHINJzR5wHTsfKZTtcOVoEGj6yX3ed7yLQ92KR4QO9KjlrlO7/Y7766i7Tw==", + "license": "MIT", + "dependencies": { + "bsert": "~0.0.12" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/bs32": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/bs32/-/bs32-0.1.7.tgz", + "integrity": "sha512-I0aKZCBneFTkcVNUIALzsOevqPIF93ynGPX6wj6pXmIBpXVGCqTgdvMx2QyR/NwgOIqMLH++Ovyum28abVG6QA==", + "license": "MIT", + "dependencies": { + "bsert": "~0.0.10" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/bsert": { + "version": "0.0.13", + "resolved": "https://registry.npmjs.org/bsert/-/bsert-0.0.13.tgz", + "integrity": "sha512-gYzSj8I2lDTKvl4aRSYs2CZIpeJugq7RjGhLRG+Jl//gEW5B2u1MKB6exVCL09FqYj6JRQAAgRwQHMOWvr7A8A==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/bsock": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/bsock/-/bsock-0.1.11.tgz", + "integrity": "sha512-4COhlKKBfOQOomNvz1hjoPtN5ytpqbxkuCPvIPbYMvaZwNBKpo8dZa1LJjcN3wuAkjIIJLF/fc4o3e1DYiceQw==", + "license": "MIT", + "dependencies": { + "bsert": "~0.0.12" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/bsocks": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bsocks/-/bsocks-0.2.6.tgz", + "integrity": "sha512-66UkjoB9f7lhT+WKgYq8MQa6nkr96mlX64JYMlIsXe/X4VeqNwvsx7UOE3ZqD6lkwg8GvBhapRTWj0qWO3Pw8w==", + "license": "MIT", + "dependencies": { + "binet": "~0.3.5", + "bsert": "~0.0.10" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/btcp": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/btcp/-/btcp-0.1.5.tgz", + "integrity": "sha512-tkrtMDxeJorn5p0KxaLXELneT8AbfZMpOFeoKYZ5qCCMMSluNuwut7pGccLC5YOJqmuk0DR774vNVQLC9sNq/A==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/budp": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/budp/-/budp-0.1.6.tgz", + "integrity": "sha512-o+a8NPq3DhV91j4nInjht2md6mbU1XL+7ciPltP66rw5uD3KP1m5r8lA94LZVaPKcFdJ0l2HVVzRNxnY26Pefg==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-map": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/buffer-map/-/buffer-map-0.0.8.tgz", + "integrity": "sha512-RlxrBAk98CqJdwSPgXOWYbC85xuq4H4vyGmW68BJ9IAGkCHQKC+flavb+d3LGxiDluczbTG8NhgKBRllpFGurA==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/bufio": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/bufio/-/bufio-1.0.7.tgz", + "integrity": "sha512-bd1dDQhiC+bEbEfg56IdBv7faWa6OipMs/AFFFvtFnB3wAYjlwQpQRZ0pm6ZkgtfL0pILRXhKxOiQj6UzoMR7A==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/bupnp": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bupnp/-/bupnp-0.2.6.tgz", + "integrity": "sha512-J6ykzJhZMxXKN78K+1NzFi3v/51X2Mvzp2hW42BWwmxIVfau6PaN99gyABZ8x05e8MObWbsAis23gShhj9qpbw==", + "license": "MIT", + "dependencies": { + "binet": "~0.3.5", + "brq": "~0.1.7", + "bsert": "~0.0.10" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/bval": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/bval/-/bval-0.1.8.tgz", + "integrity": "sha512-38WQyq94sgKaJbHSmkOwZqba6Ac0KIKPO0SMDNg/mCcwUos2NIrMg5Bb2LkzIer+RzS186IYusNeSrJrKdaqhA==", + "license": "MIT", + "dependencies": { + "bsert": "~0.0.10" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/bweb": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bweb/-/bweb-0.2.0.tgz", + "integrity": "sha512-JfpXemYqylNySwrhR7b4HZTrxnDhbOzNiIXCPBVQU6O8rTZ1wFDLFDr/7uQqkwzjyNZ4ZWTp5wP/pJY2IizfDA==", + "license": "MIT", + "dependencies": { + "bsert": "~0.0.10", + "bsock": "~0.1.9" + }, + "bin": { + "bweb": "bin/bweb" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/chai": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", + "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", + "license": "MIT", + "peer": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chai-as-promised": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", + "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", + "license": "WTFPL", + "dependencies": { + "check-error": "^1.0.2" + }, + "peerDependencies": { + "chai": ">= 2.1.2 < 5" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "license": "MIT" + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-table3": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.0.tgz", + "integrity": "sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ==", + "license": "MIT", + "dependencies": { + "object-assign": "^4.1.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "colors": "^1.1.2" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "license": "ISC", + "engines": { + "node": ">= 10" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/commander": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.0.0.tgz", + "integrity": "sha512-ovx/7NkTrnPuIV8sqk/GjUIIM1+iUQeqA3ye2VNpq9sVoiZsooObWlQy+OPWGI17GDaEoybuAGJm6U8yC077BA==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", + "license": "MIT", + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/date-fns": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.17.0.tgz", + "integrity": "sha512-ZEhqxUtEZeGgg9eHNSOAJ8O9xqSgiJdrL0lzSSfMF54x6KXWJiOH/xntSJ9YomJPrYH/p08t6gWjGWq1SDJlSA==", + "license": "MIT", + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/deep-eql": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "license": "MIT", + "peer": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deferred-leveldown": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz", + "integrity": "sha512-a59VOT+oDy7vtAbLRCZwWgxu2BaCfd5Hk7wxJd48ei7I+nsg8Orlb9CLG0PMZienk9BSUKgeAqkO2+Lw+1+Ukw==", + "deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)", + "license": "MIT", + "dependencies": { + "abstract-leveldown": "~6.2.1", + "inherits": "^2.0.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/encoding-down": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-6.3.0.tgz", + "integrity": "sha512-QKrV0iKR6MZVJV08QY0wp1e7vF6QbhnbQhb07bwpEyuz4uZiZgPlEGdkCROuFkUwdxlFaiPIhjyarH1ee/3vhw==", + "deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)", + "license": "MIT", + "dependencies": { + "abstract-leveldown": "^6.2.1", + "inherits": "^2.0.3", + "level-codec": "^9.0.0", + "level-errors": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "license": "MIT", + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "license": "MIT", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/goosig": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/goosig/-/goosig-0.10.0.tgz", + "integrity": "sha512-+BVVLfxmawAmGVjjJpXzu5LNcFIOfgXgP7kWEyc3qu/xn9RMqbPbNfYDdHBZKfZkDMIO7Q4vD790iNYQAXhoFA==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "bcrypto": "~5.4.0", + "bsert": "~0.0.10", + "loady": "~0.0.5" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hsd": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/hsd/-/hsd-7.0.1.tgz", + "integrity": "sha512-5zju8h08RYENrmFZ5jBsclGt3VC5mH3s/TmNHNtc/EwuOaYnydyY+BfSiNPIaEsBsKVWgcXkb+8btigoB7CGbQ==", + "license": "MIT", + "dependencies": { + "@handshake-org/bfilter": "~2.3.0", + "bcfg": "~0.2.2", + "bcrypto": "~5.4.0", + "bcurl": "~0.2.1", + "bdb": "~1.6.1", + "bdns": "~0.1.5", + "bevent": "~0.1.6", + "bfile": "~0.2.3", + "bheep": "~0.1.6", + "binet": "~0.3.9", + "blgr": "~0.2.1", + "blru": "~0.1.8", + "blst": "~0.1.6", + "bmutex": "~0.1.7", + "bns": "~0.15.0", + "bsert": "~0.0.13", + "bsock": "~0.1.11", + "bsocks": "~0.2.6", + "btcp": "~0.1.5", + "buffer-map": "~0.0.8", + "bufio": "~1.2.2", + "bupnp": "~0.2.6", + "bval": "~0.1.8", + "bweb": "~0.2.0", + "goosig": "~0.10.0", + "n64": "~0.2.10", + "urkel": "~1.0.3" + }, + "bin": { + "hs-seeder": "bin/hs-seeder", + "hs-wallet": "bin/hsw", + "hsd": "bin/hsd", + "hsd-cli": "bin/hsd-cli", + "hsd-node": "bin/node", + "hsd-rpc": "bin/hsd-rpc", + "hsd-spvnode": "bin/spvnode", + "hsw-cli": "bin/hsw-cli", + "hsw-rpc": "bin/hsw-rpc" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/hsd/node_modules/bcurl": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/bcurl/-/bcurl-0.2.1.tgz", + "integrity": "sha512-7L00pT9SQEDzRIsRn53Il5pYHkeFlIoH0SdNIAbXdqsUMnq4IteTRuSZwC2f/uUKiRE5oW40MBhW72mquO9sQg==", + "license": "MIT", + "dependencies": { + "brq": "~0.1.10", + "bsert": "~0.0.12", + "bsock": "~0.1.10" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/hsd/node_modules/bufio": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bufio/-/bufio-1.2.3.tgz", + "integrity": "sha512-5Tt66bRzYUSlVZatc0E92uDenreJ+DpTBmSAUwL4VSxJn3e6cUyYwx+PoqML0GRZatgA/VX8ybhxItF8InZgqA==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/immediate": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", + "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==", + "license": "MIT" + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/level": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/level/-/level-6.0.1.tgz", + "integrity": "sha512-psRSqJZCsC/irNhfHzrVZbmPYXDcEYhA5TVNwr+V92jF44rbf86hqGp8fiT702FyiArScYIlPSBTDUASCVNSpw==", + "license": "MIT", + "dependencies": { + "level-js": "^5.0.0", + "level-packager": "^5.1.0", + "leveldown": "^5.4.0" + }, + "engines": { + "node": ">=8.6.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/level" + } + }, + "node_modules/level-codec": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-9.0.2.tgz", + "integrity": "sha512-UyIwNb1lJBChJnGfjmO0OR+ezh2iVu1Kas3nvBS/BzGnx79dv6g7unpKIDNPMhfdTEGoc7mC8uAu51XEtX+FHQ==", + "deprecated": "Superseded by level-transcoder (https://github.com/Level/community#faq)", + "license": "MIT", + "dependencies": { + "buffer": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/level-concat-iterator": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz", + "integrity": "sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw==", + "deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/level-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-2.0.1.tgz", + "integrity": "sha512-UVprBJXite4gPS+3VznfgDSU8PTRuVX0NXwoWW50KLxd2yw4Y1t2JUR5In1itQnudZqRMT9DlAM3Q//9NCjCFw==", + "deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)", + "license": "MIT", + "dependencies": { + "errno": "~0.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/level-iterator-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-4.0.2.tgz", + "integrity": "sha512-ZSthfEqzGSOMWoUGhTXdX9jv26d32XJuHz/5YnuHZzH6wldfWMOVwI9TBtKcya4BKTyTt3XVA0A3cF3q5CY30Q==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.4.0", + "xtend": "^4.0.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/level-js": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/level-js/-/level-js-5.0.2.tgz", + "integrity": "sha512-SnBIDo2pdO5VXh02ZmtAyPP6/+6YTJg2ibLtl9C34pWvmtMEmRTWpra+qO/hifkUtBTOtfx6S9vLDjBsBK4gRg==", + "deprecated": "Superseded by browser-level (https://github.com/Level/community#faq)", + "license": "MIT", + "dependencies": { + "abstract-leveldown": "~6.2.3", + "buffer": "^5.5.0", + "inherits": "^2.0.3", + "ltgt": "^2.1.2" + } + }, + "node_modules/level-packager": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/level-packager/-/level-packager-5.1.1.tgz", + "integrity": "sha512-HMwMaQPlTC1IlcwT3+swhqf/NUO+ZhXVz6TY1zZIIZlIR0YSn8GtAAWmIvKjNY16ZkEg/JcpAuQskxsXqC0yOQ==", + "deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)", + "license": "MIT", + "dependencies": { + "encoding-down": "^6.3.0", + "levelup": "^4.3.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/level-supports": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-1.0.1.tgz", + "integrity": "sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/leveldown": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-5.6.0.tgz", + "integrity": "sha512-iB8O/7Db9lPaITU1aA2txU/cBEXAt4vWwKQRrrWuS6XDgbP4QZGj9BL2aNbwb002atoQ/lIotJkfyzz+ygQnUQ==", + "deprecated": "Superseded by classic-level (https://github.com/Level/community#faq)", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "abstract-leveldown": "~6.2.1", + "napi-macros": "~2.0.0", + "node-gyp-build": "~4.1.0" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/levelup": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/levelup/-/levelup-4.4.0.tgz", + "integrity": "sha512-94++VFO3qN95cM/d6eBXvd894oJE0w3cInq9USsyQzzoJxmiYzPAocNcuGCPGGjoXqDVJcr3C1jzt1TSjyaiLQ==", + "deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)", + "license": "MIT", + "dependencies": { + "deferred-leveldown": "~5.3.0", + "level-errors": "~2.0.0", + "level-iterator-stream": "~4.0.0", + "level-supports": "~1.0.0", + "xtend": "~4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/loady": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/loady/-/loady-0.0.5.tgz", + "integrity": "sha512-uxKD2HIj042/HBx77NBcmEPsD+hxCgAtjEWlYNScuUjIsh/62Uyu39GOR68TBR68v+jqDL9zfftCWoUo4y03sQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "license": "MIT", + "peer": true, + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/ltgt": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz", + "integrity": "sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA==", + "license": "MIT" + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "license": "ISC" + }, + "node_modules/n64": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/n64/-/n64-0.2.10.tgz", + "integrity": "sha512-uH9geV4+roR1tohsrrqSOLCJ9Mh1iFcDI+9vUuydDlDxUS1UCAWUfuGb06p3dj3flzywquJNrGsQ7lHP8+4RVQ==", + "license": "MIT", + "engines": { + "node": ">=2.0.0" + } + }, + "node_modules/napi-macros": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", + "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==", + "license": "MIT" + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "license": "MIT", + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/node-gyp-build": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.1.1.tgz", + "integrity": "sha512-dSq1xmcPDKPZ2EED2S6zw/b9NKsqzXRE6dVr8TVQnI3FJOTteUMuqF3Qqs6LZg+mLGYJWqQzMbIjMtJqTv87nQ==", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/password-prompt": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/password-prompt/-/password-prompt-1.1.2.tgz", + "integrity": "sha512-bpuBhROdrhuN3E7G/koAju0WjVw9/uQOG5Co5mokNj0MiOSBVZS1JTwM4zl55hu0WFmIEFvO9cU9sJQiBIYeIA==", + "license": "WTFPL", + "dependencies": { + "ansi-escapes": "^3.1.0", + "cross-spawn": "^6.0.5" + } + }, + "node_modules/password-prompt/node_modules/ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/shakedex": { + "version": "0.0.19", + "resolved": "https://registry.npmjs.org/shakedex/-/shakedex-0.0.19.tgz", + "integrity": "sha512-s5Wjz2aTvOiT+6cQAqAJ7NtVZi/mrB9eANicTNs5yMeG0ecpIFrwBwxS1vbAwZlQeW0DJ+YgvnCtzNf0OZxpQw==", + "license": "MIT", + "dependencies": { + "bcrypto": "5.4.0", + "bcurl": "^0.1.9", + "chai-as-promised": "7.1.1", + "cli-table3": "0.6.0", + "commander": "7.0.0", + "date-fns": "2.17.0", + "inquirer": "7.3.3", + "level": "6.0.1", + "node-fetch": "2.6.1", + "password-prompt": "1.1.2", + "tar": "6.1.0" + }, + "bin": { + "shakedex": "bin/shakedex" + } + }, + "node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", + "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==", + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "license": "MIT" + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unbound": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/unbound/-/unbound-0.4.3.tgz", + "integrity": "sha512-2ISqZLXtzp1l9f1V8Yr6S+zuhXxEwE1CjKHjXULFDHJcfhc9Gm3mn19hdPp4rlNGEdCivKYGKjYe3WRGnafYdA==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "loady": "~0.0.5" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/urkel": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/urkel/-/urkel-1.0.3.tgz", + "integrity": "sha512-L2M46WWSaz1LpyUYFgnQg7WSOWtNcRx3uH+4GwHK1jbmYj6phLuIwirTVMlhfcZ0o/CWn5Y04UWLhmlvijZiDg==", + "license": "MIT", + "dependencies": { + "bfile": "~0.2.1", + "bmutex": "~0.1.6", + "bsert": "~0.0.10" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..307b636 --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "name": "firesales-plugin", + "version": "1.0.0", + "description": "FireSales Plugin", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://git.woodburn.au/nathanwoodburn/firesales-plugin.git" + }, + "author": "Nathan.Woodburn/", + "license": "AGPL-3.0-only", + "dependencies": { + "hsd": "^7.0.1", + "shakedex": "^0.0.19" + } +} diff --git a/shakedex/context.js b/shakedex/context.js new file mode 100644 index 0000000..62e61ac --- /dev/null +++ b/shakedex/context.js @@ -0,0 +1,77 @@ +const { NodeClient, WalletClient } = require('hsd/lib/client'); +const Network = require('hsd/lib/protocol/network.js'); +const passwordPrompt = require('password-prompt'); + +class Context { + constructor( + networkName, + walletId, + apiKey, + passphraseGetter = noopPassphraseGetter, + host = '127.0.0.1', + nodeApiKey, + ) { + this.networkName = networkName; + this.network = Network.get(networkName); + this.walletId = walletId; + this.nodeClient = new NodeClient({ + port: this.network.rpcPort, + host, + apiKey: nodeApiKey || apiKey, + }); + this.walletClient = new WalletClient({ + port: this.network.walletPort, + host, + apiKey: apiKey, + }); + this.wallet = this.walletClient.wallet(walletId); + this.passphraseGetter = passphraseGetter; + } + + getPassphrase = () => { + return this.passphraseGetter(); + }; + + execNode = (method, ...args) => { + return this.nodeClient.execute(method, args); + }; + + execWallet = async (method, ...args) => { + await this.walletClient.execute('selectwallet', [this.walletId]); + return this.walletClient.execute(method, args); + }; + + unlockWallet = async () => { + const pass = await this.getPassphrase(); + if (pass === null) { + return; + } + await this.wallet.unlock(pass, 60); + }; + + getMTP = async () => { + const info = await this.execNode('getblockchaininfo'); + return info.mediantime; + }; + + getHeight = async () => { + const info = await this.execNode('getblockchaininfo'); + return info.blocks; + }; +} + +exports.Context = Context; + +exports.staticPassphraseGetter = function (passphrase) { + return () => new Promise((resolve) => resolve(passphrase)); +}; + +function noopPassphraseGetter() { + return new Promise((resolve) => resolve(null)); +} + +exports.promptPassphraseGetter = function ( + prefix = '>> Please enter your passphrase: ' +) { + return () => new Promise((resolve) => resolve(passwordPrompt(prefix))); +}; diff --git a/shakedex/main.js b/shakedex/main.js new file mode 100644 index 0000000..907e9e4 --- /dev/null +++ b/shakedex/main.js @@ -0,0 +1,1058 @@ +const {program} = require('commander'); +const pkg = require('../../package.json'); +const {transferNameLock} = require('../swapService.js'); +const {Context, promptPassphraseGetter} = require('../context.js'); +const Table = require('cli-table3'); +const {finalizeNameLock} = require('../swapService.js'); +const inquirer = require('inquirer'); +const fs = require('fs'); +const {log, die} = require('./util.js'); +const {postAuction} = require('../swapService.js'); +const {staticPassphraseGetter} = require('../context.js'); +const {SwapFinalize} = require('../swapFinalize.js'); +const {SwapFill} = require('../swapFill.js'); +const {NameLockCancelFinalize} = require('../nameLock.js'); +const {finalizeNameLockCancel} = require('../swapService.js'); +const {NameLockCancelTransfer} = require('../nameLock.js'); +const {transferNameLockCancel} = require('../swapService.js'); +const {linearReductionStrategy} = require('../auction.js'); +const {AuctionFactory, Auction} = require('../auction.js'); +const {NameLockTransfer, NameLockFinalize} = require('../nameLock.js'); +const {createLevelStore, migrate} = require('../dataStore.js'); +const {finalizeSwap} = require('../swapService.js'); +const {fillSwap} = require('../swapService.js'); +const {format} = require('date-fns'); +const Network = require('hsd/lib/protocol/network.js'); +const {NameLockExternalTransfer} = require('../nameLock.js'); +const {createNameLockExternal} = require('../swapService.js'); +const {getPostFeeInfo} = require('../swapService.js'); +const {backupDb} = require('../backup.js'); + +const DEFAULT_FEE_INFO = { + rate: 0, + addr: null, +}; + +program + .version(pkg.version) + .option( + '-p, --prefix ', + 'Prefix directory to write the database to.', + `${process.env.HOME}/.shakedex`, + ) + .option( + '-n, --network ', + 'Handshake network to connect to.', + 'regtest', + ) + .option('-w, --wallet-id ', 'Handshake wallet ID.', 'primary') + .option('-a, --api-key ', 'Handshake wallet API key.') + .option( + '--shakedex-web-host ', + 'Shakedex web hostname.', + 'https://api.shakedex.com', + ) + .option('--no-passphrase', 'Disable prompts for the wallet passphrase.') + .option('-H, --httphost ', 'HSD Host.', '127.0.0.1'); + +program + .command('create-external-lock ') + .description( + 'Creates an address to directly finalize a name transfer to.', + ) + .action(createExternalLock); + +program + .command('external-lock-details ') + .description( + 'Prints details about an external lock.', + ) + .action(viewExternalLock); + + +program + .command('transfer-lock ') + .description( + 'Posts a name lock transaction, which when finalized allows the name to be auctioned.', + ) + .action(transferLock); + +program + .command('finalize-lock ') + .description( + 'Finalizes a name lock transaction, which allows the name to be auctioned.', + ) + .action(finalizeLock); + +program + .command('transfer-lock-cancel ') + .description( + 'Begins cancelling a name lock by transferring it back to the sender.', + ) + .action(transferLockCancel); + +program + .command('finalize-lock-cancel ') + .description('Cancels a name lock by finalizing it back to the sender.') + .action(finalizeLockCancel); + +program + .command('create-auction ') + .description('Creates auction presigns.') + .action(createAuction); + +program + .command('publish-auction ') + .description('Uploads an auction file to Shakedex Web.') + .action(publishAuction); + +program + .command('list-auctions') + .description('Prints all of your auctions and their statuses.') + .action(listAuctions); + +program + .command('auction-details ') + .description('Prints details of a specific name auction.') + .action(auctionDetails); + +program + .command('fill-auction ') + .description('Fills an auction.') + .action(fillAuction); + +program + .command('finalize-auction ') + .description('Finalizes an auction that has been previously fulfilled.') + .action(finalizeAuction); + +program + .command('inspect-auction ') + .description('Decode proofs file and display auction information.') + .action(inspectAuction); + +program + .command('list-fills') + .description('Prints all of your fills and their statuses.') + .action(listFills); + +program + .command('backup ') + .description('Backs up the shakedex internal DB.') + .action(backup); + +program.parse(process.argv); + +function setupPrefix(prefix) { + if (fs.existsSync(prefix)) { + return; + } + fs.mkdirSync(prefix); +} + +function getContext(opts) { + return new Context( + opts.network, + opts.walletId, + opts.apiKey, + opts.passphrase ? promptPassphraseGetter() : staticPassphraseGetter(null), + opts.httphost, + ); +} + +async function setupCLI() { + const opts = program.opts(); + + let out = {}; + try { + setupPrefix(opts.prefix); + } catch (e) { + console.error('An error occurred. Stack trace:'); + console.error(e); + console.error(); + console.error( + `Please report this as an issue by visiting ${pkg.bugs.url}/new.`, + ); + throw e; + } + + try { + Network.get(opts.network); + } catch (e) { + die(`Invalid network ${opts.network}.`); + return; + } + + out.context = getContext(opts); + + await migrate(opts.prefix); + + out.db = await createLevelStore(opts.prefix, opts.network); + out.opts = opts; + return out; +} + +async function confirm(message, shouldDie = true) { + const answers = await inquirer.prompt([ + { + type: 'confirm', + name: 'confirmed', + message, + }, + ]); + + if (shouldDie && !answers.confirmed) { + die('Cancelled.'); + } + + return answers.confirmed; +} + +async function createExternalLock(name) { + const {db, context} = await setupCLI(); + + await confirm( + `This command will create an address for a third party to transfer your name to.`, + ); + + log('Creating external locking addr.'); + const lock = await createNameLockExternal(context, name); + await db.putLockExternalTransfer(lock); + log('Locking address successfully created. Give the following address to whoever holds your name:'); + log(lock.lockScriptAddr.toString(context.networkName)); +} + +async function viewExternalLock(name) { + const {db, context} = await setupCLI(); + + const extLockJSON = await db.getLockExternalTransfer(name); + if (!extLockJSON) { + throw new Error( + `Lock info for ${name} was not found.`, + ); + } + const extTransfer = new NameLockExternalTransfer(extLockJSON); + const confirmation = await extTransfer.getConfirmationDetails(context); + + const table = new Table(); + table.push( + { + Name: extTransfer.name, + }, + { + 'Locking Address': extTransfer.lockScriptAddr.toString(context.networkName), + }, + { + 'Confirmed At': confirmation.confirmedAt + ? format(new Date(confirmation.confirmedAt), 'MM/dd/yyyy HH:MM:SS') + : '-', + }, + { + 'Finalize TX Hash': confirmation.confirmedAt ? confirmation.finalizeTxHash : '-', + }, + { + 'Finalize Output Idx': confirmation.confirmedAt ? confirmation.finalizeOutputIdx : '-', + }, + ); + process.stdout.write(table.toString()); + process.stdout.write('\n'); +} + +async function transferLock(name) { + const {db, context} = await setupCLI(); + + await confirm( + `Your name ${name} will be transferred to a locking script. ` + + 'This can be undone, but requires additional on-chain transactions. Do you wish to continue?', + ); + + log('Performing locking script transfer.'); + const lockTransfer = await transferNameLock(context, name); + await db.putLockTransfer(lockTransfer); + log( + `Name transferred to locking script with transaction hash ${lockTransfer.transferTxHash.toString( + 'hex', + )}.`, + ); + log('Please wait at least 15 minutes for your transaction to be confirmed.'); +} + +async function finalizeLock(name) { + const {db, context} = await setupCLI(); + + await confirm( + `Your transfer of ${name} to the locking script will be finalized. ` + + 'This can be undone, but requires additional on-chain transactions. Do you wish to continue?', + ); + + const nameState = await db.getOutboundNameState(name); + if (nameState === null) { + die(`Name ${name} not found.`); + } + if (nameState !== 'TRANSFER') { + die(`Name ${name} is not in the TRANSFER state.`); + } + + const transferJSON = await db.getLockTransfer(name); + if (!transferJSON) { + throw new Error( + `Name transfer for ${name} was not found. This implies database corruption; please file an issue.`, + ); + } + const transfer = new NameLockTransfer(transferJSON); + const confirmed = await transfer.getConfirmationDetails(context); + if (!confirmed.confirmedAt) { + die( + `The transaction transferring ${name} to the locking script is unconfirmed. Please try again later.`, + ); + } + if (!confirmed.spendable) { + die( + `The transfer of ${name} to the locking script is in the lockup period. Please try again in ${confirmed.spendableIn} blocks.`, + ); + } + + log('Finalizing locking script transfer.'); + const lockFinalize = await finalizeNameLock(context, transfer); + await db.putLockFinalize(lockFinalize); + log( + `Name finalized to locking script with transaction hash ${lockFinalize.finalizeTxHash}.`, + ); + log('Please wait at least 15 minutes for your transaction to be confirmed.'); +} + +async function transferLockCancel(name) { + await confirm( + `Your transfer of ${name} to the locking script will be cancelled. You will need to finalize this ` + + 'transfer to regain ownership of the name. Do you wish to continue?', + ); + + const {db, context} = await setupCLI(); + + const nameState = await db.getOutboundNameState(name); + if (nameState === null) { + die(`Name ${name} not found.`); + } + if (nameState !== 'FINALIZE' && nameState !== 'AUCTION') { + die(`Name ${name} is not in the FINALIZE or AUCTION state.`); + } + if (nameState === 'AUCTION') { + await confirm( + 'WARNING! Your auction is already live. If someone redeems one of your pre-signed auction ' + + 'transactions, your name name will be irrevocably transferred to them. Do you understand this?', + ); + } + + const finalizeJSON = await db.getLockFinalize(name); + const finalize = new NameLockFinalize(finalizeJSON); + const transferCancel = await transferNameLockCancel(context, finalize); + await db.putLockCancelTransfer(context, transferCancel); + log( + `Name lock transferred back to seller with transaction hash ${transferCancel.transferTxHash.toString( + 'hex', + )}.`, + ); + log('Please wait 15 minutes for your transaction to be confirmed.'); +} + +async function finalizeLockCancel(name) { + const {db, context} = await setupCLI(); + + const nameState = await db.getOutboundNameState(name); + if (nameState !== 'CANCEL_TRANSFER') { + die(`Name $[name} is not in the CANCEL_TRANSFER state.`); + } + + const transferJSON = await db.getLockCancelTransfer(name); + const transfer = new NameLockCancelTransfer(transferJSON); + const finalize = await finalizeNameLockCancel(context, transfer); + await db.putLockCancelFinalize(finalize); + log( + `Name lock finalized back to seller with transaction hash ${finalize.finalizeTxHash.toString( + 'hex', + )}.`, + ); + log('Please wait 15 minutes for your transaction to be confirmed.'); +} + +async function createAuction(name) { + const {db, opts, context} = await setupCLI(); + const shakedexWebHost = opts.shakedexWebHost; + + const nameState = await db.getOutboundNameState(name); + if (nameState === null) { + die(`Name ${name} not found.`); + } + if (nameState !== 'EXTERNAL_TRANSFER' && nameState !== 'FINALIZE' && nameState !== 'AUCTION') { + die(`Name ${name} is not in the EXTERNAL_TRANSFER, FINALIZE, or AUCTION state.`); + } + + if (nameState === 'AUCTION') { + const overwriteOkAnswer = await inquirer.prompt([ + { + type: 'confirm', + name: 'overwriteOk', + message: `You have already created an auction for ${name}. Do you want to overwrite it?`, + default: true, + }, + ]); + + if (!overwriteOkAnswer.overwriteOk) { + die('Aborted.'); + } + } + + let finalize; + if (nameState === 'EXTERNAL_TRANSFER') { + const extTransferJSON = await db.getLockExternalTransfer(name); + const extTransfer = new NameLockExternalTransfer(extTransferJSON); + const confirmation = await extTransfer.getConfirmationDetails(context); + if (!confirmation.confirmedAt) { + die( + `The transaction finalizing ${name} to the locking script is unconfirmed. Please try again later.`, + ); + } + finalize = new NameLockFinalize({ + name: extTransfer.name, + finalizeTxHash: confirmation.finalizeTxHash, + finalizeOutputIdx: confirmation.finalizeOutputIdx, + privateKey: extTransfer.privateKey, + broadcastAt: confirmation.confirmedAt * 1000, + }); + } else { + const finalizeJSON = await db.getLockFinalize(name); + finalize = new NameLockFinalize(finalizeJSON); + const confirmation = await finalize.getConfirmationDetails(context); + if (!confirmation.confirmedAt) { + die( + `The transaction finalizing ${name} to the locking script is unconfirmed. Please try again later.`, + ); + } + } + + const {outPath, auction, shouldPost} = await promptAuctionParameters( + db, + context, + finalize, + shakedexWebHost, + ); + + const stream = fs.createWriteStream(outPath); + await auction.writeToStream(context, stream); + + if (shouldPost) { + try { + await postAuction(context, auction, shakedexWebHost); + } catch (e) { + log('An error occurred posting your proof to Shakedex Web:'); + log(e.message); + log(e.stack); + log(`You can still find your proof in ${outPath}.`); + } + } + + await db.putAuction(context, auction); + + log(`Your auction has been successfully written to ${outPath}.`); +} + +async function publishAuction(auctionFile) { + const exists = fs.existsSync(auctionFile); + if (!exists) { + die(`Auction file not found.`); + } + + const {opts, context} = await setupCLI(); + const readStream = await fs.readFileSync(auctionFile); + const auction = await Auction.fromStream(readStream); + + try { + await postAuction(context, auction, opts.shakedexWebHost); + } catch (e) { + log('An error occurred posting your proof to Shakedex Web:'); + log(e.message); + log(e.stack); + return; + } + + log(`Your auction for ${auction.name} was successfully posted to ${opts.shakedexWebHost}.`); + log(`Link: https://${opts.shakedexWebHost}/a/${auction.name}`); +} + +async function promptAuctionParameters(db, context, finalize, shakedexWebHost) { + const {name} = finalize; + + const answers = await inquirer.prompt([ + { + type: 'list', + name: 'duration', + message: 'How long should the auction last?', + choices: ['1 day', '3 days', '5 days', '7 days', '14 days'], + }, + { + type: 'list', + name: 'decrementInterval', + message: 'How often would you like the price to decrease?', + choices: ['Every 15 minutes', 'Every 30 minutes', 'Hourly', 'Daily'], + }, + { + type: 'input', + name: 'startPrice', + message: + 'What price would you like to start the auction at? This should be a high price. Expressed in whole HNS.', + validate: (value) => { + const valid = !isNaN(Number(value)) && Number(value) > 0; + if (valid) { + return true; + } + return `Invalid start price.`; + }, + }, + { + type: 'input', + name: 'endPrice', + message: + 'What price would you like to end the auction at? This is the lowest price you will accept for the name. Expressed in whole HNS.', + validate: (value) => { + const valid = !isNaN(Number(value)) && Number(value) > 0; + if (valid) { + return true; + } + return `Invalid end price.`; + }, + }, + { + type: 'input', + name: 'outPath', + message: 'Where would you like to store your auction presigns?', + }, + { + type: 'confirm', + name: 'shouldPost', + message: `Would you like to publish your auction to Shakedex Web at ${shakedexWebHost}?`, + default: true, + }, + ]); + + const durationDays = Number(answers.duration.split(' ')[0]); + const decrementInterval = answers.decrementInterval; + const startPrice = Number(answers.startPrice); + const endPrice = Number(answers.endPrice); + if (startPrice < endPrice) { + die('Your start price cannot be less than your end price.'); + } + + let reductionTime; + switch (decrementInterval) { + case 'Every 15 minutes': + reductionTime = 15 * 60; + break; + case 'Every 30 minutes': + reductionTime = 30 * 60; + break; + case 'Hourly': + reductionTime = 60 * 60; + break; + case 'Daily': + reductionTime = 24 * 60 * 60; + } + + let outPath = answers.outPath; + if (answers.outPath[0] === '~') { + outPath = outPath.replace('~', process.env.HOME); + } + + let feeInfo = DEFAULT_FEE_INFO; + let shouldPost = answers.shouldPost; + + if (shouldPost) { + try { + feeInfo = await getPostFeeInfo(context, shakedexWebHost); + } catch (e) { + log('An error occurred while getting fee info; not posting to Shakedex Web.'); + } + + if (feeInfo.rate !== 0) { + const feeOk = await confirm( + `The ShakeDex Web host at ${shakedexWebHost} charges a fee of ${feeInfo.rate / 100}%. Is this OK? ` + + `Buyers will pay this fee. If you decline, your auction's presigns will still be generated with ` + + `a fee of zero. They will not be uploaded to the auction site.`, + false, + ); + + if (!feeOk) { + feeInfo = DEFAULT_FEE_INFO; + shouldPost = false; + } + } + } + + const mtp = await context.getMTP(); + const auctionFactory = new AuctionFactory({ + name, + startTime: mtp, + endTime: mtp + durationDays * 24 * 60 * 60, + startPrice: startPrice * 1e6, + endPrice: endPrice * 1e6, + reductionTime, + reductionStrategy: linearReductionStrategy, + feeRate: feeInfo.rate, + feeAddr: feeInfo.addr, + }); + + const auction = await auctionFactory.createAuction(context, finalize); + + log(`Please confirm your auction's pricing parameters below.`); + const table = new Table({ + head: ['Price', 'Fee', 'Unlocks At'], + }); + for (const datum of auction.data) { + table.push([ + (datum.price / 1e6).toFixed(6), + (datum.fee / 1e6).toFixed(6), + format(new Date(datum.lockTime * 1000), 'MM/dd/yyyy HH:MM:SS'), + ]); + } + + process.stdout.write(table.toString()); + process.stdout.write('\n'); + + const paramsOkAnswer = await inquirer.prompt([ + { + type: 'confirm', + name: 'paramsOk', + message: 'Do these auction pricing parameters look ok?', + default: true, + }, + ]); + + if (!paramsOkAnswer.paramsOk) { + return promptAuctionParameters(db, context, finalize, shakedexWebHost); + } + + return {outPath, auction, shouldPost}; +} + +async function listAuctions() { + const {db, context} = await setupCLI(); + + const table = new Table({ + head: [ + 'Name', + 'Status', + 'Confirmed', + 'Lockup', + 'Broadcast At', + 'Confirmed At', + ], + }); + + const names = []; + await db.iterateOutboundNames((key, value) => { + const keySplits = key.split('/'); + const name = keySplits[keySplits.length - 1]; + const version = Number(value); + names.push([name, version]); + }); + + for (const [name, version] of names) { + const state = await db.getOutboundNameState(name, version); + + switch (state) { + case 'EXTERNAL_TRANSFER': { + const transfer = new NameLockExternalTransfer( + await db.getLockExternalTransfer(name, version), + ); + const confirmation = await transfer.getConfirmationDetails(context); + table.push([ + name, + `EXTERNAL_TRANSFER_${confirmation.status}`, + confirmation.status === 'CONFIRMED' ? 'YES' : 'NO', + 'N/A', + 'N/A', + confirmation.confirmedAt + ? format(new Date(confirmation.confirmedAt), 'MM/dd/yyyy HH:MM:SS') + : '-', + ]); + break; + } + case 'TRANSFER': { + const transfer = new NameLockTransfer( + await db.getLockTransfer(name, version), + ); + const confirmation = await transfer.getConfirmationDetails(context); + table.push([ + name, + state, + confirmation.confirmedAt ? 'YES' : 'NO', + confirmation.confirmedAt + ? confirmation.spendable + ? '0 BLOCKS' + : `${confirmation.spendableIn} BLOCKS` + : '-', + format(new Date(transfer.broadcastAt), 'MM/dd/yyyy HH:MM:SS'), + confirmation.confirmedAt + ? format(new Date(confirmation.confirmedAt), 'MM/dd/yyyy HH:MM:SS') + : '-', + ]); + break; + } + case 'FINALIZE': { + const finalize = new NameLockFinalize( + await db.getLockFinalize(name, version), + ); + const confirmation = await finalize.getConfirmationDetails(context); + table.push([ + name, + state, + confirmation.confirmedAt ? 'YES' : 'NO', + '-', + format(new Date(finalize.broadcastAt), 'MM/dd/yyyy HH:MM:SS'), + confirmation.confirmedAt + ? format(new Date(confirmation.confirmedAt), 'MM/dd/yyyy HH:MM:SS') + : '-', + ]); + break; + } + case 'AUCTION': { + const auction = new Auction(await db.getAuction(name, version)); + const isFulfilled = await auction.isFulfilled(context); + table.push([ + name, + isFulfilled ? 'AUCTION_FILLED' : 'AUCTION_LIVE', + isFulfilled ? 'YES' : 'NO', + '-', + '-', + '-', + ]); + break; + } + case 'CANCEL_TRANSFER': { + const cancelTransfer = new NameLockCancelTransfer( + await db.getLockCancelTransfer(name, version), + ); + const confirmation = await cancelTransfer.getConfirmationDetails( + context, + ); + table.push([ + name, + state, + confirmation.confirmedAt ? 'YES' : 'NO', + confirmation.confirmedAt + ? confirmation.spendable + ? '0 BLOCKS' + : `${confirmation.spendableIn} BLOCKS` + : '-', + format(new Date(cancelTransfer.broadcastAt), 'MM/dd/yyyy HH:MM:SS'), + confirmation.confirmedAt + ? format(new Date(confirmation.confirmedAt), 'MM/dd/yyyy HH:MM:SS') + : '-', + ]); + break; + } + case 'CANCEL_FINALIZE': { + const cancelFinalize = new NameLockCancelFinalize( + await db.getLockCancelFinalize(name, version), + ); + const confirmation = await cancelFinalize.getConfirmationDetails( + context, + ); + table.push([ + name, + state, + confirmation.confirmedAt ? 'YES' : 'NO', + '-', + format(new Date(cancelFinalize.broadcastAt), 'MM/dd/yyyy HH:MM:SS'), + confirmation.confirmedAt + ? format(new Date(confirmation.confirmedAt), 'MM/dd/yyyy HH:MM:SS') + : '-', + ]); + break; + } + } + } + + process.stdout.write(table.toString()); + process.stdout.write('\n'); +} + +async function auctionDetails(name) { + const {db, context} = await setupCLI(); + const status = await db.getOutboundNameState(name); + if (status !== 'AUCTION') { + die( + `Name ${name} is not in the AUCTION state. Run shakedex list-outbound-names to view this name.`, + ); + } + + const auctionJSON = await db.getAuction(name); + if (!auctionJSON) { + throw new Error( + `Auction for ${name} was not found. This implies database corruption; please file an issue.`, + ); + } + const auction = new Auction(auctionJSON); + const isFulfilled = await auction.isFulfilled(context); + + log('Basic info:'); + const infoTable = new Table(); + infoTable.push( + {Name: name}, + {'Locking TX Hash': auction.lockingTxHash.toString('hex')}, + {'Locking Output Idx': auction.lockingOutputIdx}, + { + 'First Bid Unlocks At': format( + new Date(auction.data[0].lockTime * 1000), + 'MM/dd/yyyy HH:MM:SS', + ), + }, + { + 'Last Bid Unlocks At': format( + new Date(auction.data[auction.data.length - 1].lockTime * 1000), + 'MM/dd/yyyy HH:MM:SS', + ), + }, + {'Starting Bid': (auction.data[0].price / 1e6).toFixed(6)}, + { + 'Ending Bid': (auction.data[auction.data.length - 1].price / 1e6).toFixed( + 6, + ), + }, + {'Fulfilled?': isFulfilled ? 'YES' : 'NO'}, + ); + process.stdout.write(infoTable.toString()); + process.stdout.write('\n'); + + log('Bid schedule:'); + const bidsTable = new Table(['Bid', 'Unlocks At']); + for (const datum of auction.data) { + bidsTable.push([ + (datum.price / 1e6).toFixed(6), + format(new Date(datum.lockTime * 1000), 'MM/dd/yyyy HH:MM:SS'), + ]); + } + process.stdout.write(bidsTable.toString()); + process.stdout.write('\n'); +} + +async function fillAuction(auctionPath) { + const exists = fs.existsSync(auctionPath); + if (!exists) { + die(`Proposals file not found.`); + } + + const {db, context} = await setupCLI(); + const readStream = await fs.readFileSync(auctionPath); + const auction = await Auction.fromStream(readStream); + + log('Verifying swap proofs.'); + const ok = await auction.verifyProofs(context, (curr, total) => { + process.stdout.clearLine(); + process.stdout.cursorTo(0); + process.stdout.write(`>> Verified proof ${curr}.`); + }); + process.stdout.clearLine(); + process.stdout.cursorTo(0); + if (!ok) { + die('Auction contains invalid swap proofs.'); + } + log('All swap proofs in auction are valid.'); + + log('Calculating best price.'); + + const [bestBid, bestProofIdx] = await auction.bestBidAt(context); + + if (!bestBid) + die('No proofs are mature yet, auction has not started.'); + + const table = new Table(); + table.push( + { + Name: bestBid.name, + }, + { + Price: `${(bestBid.price / 1e6).toFixed(6)} HNS`, + }, + { + Fee: `${(bestBid.fee / 1e6).toFixed(6)}`, + }, + ); + process.stdout.write(table.toString()); + process.stdout.write('\n'); + + await confirm( + 'Are you sure you want to fill the auction above? This action is not reversible. You are responsible for all blockchain fees.', + ); + + const fill = await fillSwap(context, auction.toSwapProof(bestProofIdx)); + await db.putSwapFill(fill); + log(`Fulfilled auction with transaction hash ${fill.fulfillmentTxHash}.`); + log(`Please wait 15 minutes for the blockchain to confirm the transaction.`); +} + +async function finalizeAuction(name) { + const {db, context} = await setupCLI(); + const status = await db.getInboundNameState(name); + if (status !== 'FILL') { + die(`Name ${name} is not in the FILL state.`); + } + + const fillJSON = await db.getSwapFill(name); + if (!fillJSON) { + throw new Error( + `Fill fo ${name} was not found. This implies database corruption; please file an issue.`, + ); + } + const fill = new SwapFill(fillJSON); + const confirmed = await fill.getConfirmationDetails(context); + if (!confirmed.confirmedAt) { + die( + `The transaction filling the ${name} auction is unconfirmed. Please try again later.`, + ); + } + if (!confirmed.spendable) { + die( + `The fill transferring ${name} to the buyer is in the lockup period. Please try again in ${confirmed.spendableIn} blocks.`, + ); + } + + const finalize = await finalizeSwap(context, fill); + await db.putSwapFinalize(finalize); +} + +async function inspectAuction(auctionPath) { + const exists = fs.existsSync(auctionPath); + if (!exists) { + die(`Proposals file not found.`); + } + + const {db, context} = await setupCLI(); + const readStream = await fs.readFileSync(auctionPath); + const auction = await Auction.fromStream(readStream); + + log('Verifying swap proofs.'); + const ok = await auction.verifyProofs(context, (curr, total) => { + process.stdout.clearLine(); + process.stdout.cursorTo(0); + process.stdout.write(`>> Verified proof ${curr}.`); + }); + process.stdout.clearLine(); + process.stdout.cursorTo(0); + if (!ok) { + die('Auction contains invalid swap proofs.'); + } + log('All swap proofs in auction are valid.'); + + const [bestBid, bestProofIdx] = await auction.bestBidAt(context); + + const table = new Table({ + head: [ + 'Name', + 'Price (HNS)', + 'Fee', + 'Locktime (MTP)', + 'Current Best' + ], + }); + for (let i = 0; i < auction.data.length; i++) { + const bid = auction.toSwapProof(i); + table.push([ + bid.name, + (bid.price / 1e6).toFixed(6), + bid.fee, + format(new Date(bid.lockTime * 1000), 'MM/dd/yyyy HH:MM:SS'), + i === bestProofIdx ? '<--------' : '' + ]); + } + process.stdout.write(table.toString()); + process.stdout.write('\n'); + + const mtp = await context.getMTP(); + const now = format(new Date(mtp * 1000), 'MM/dd/yyyy HH:MM:SS'); + log(`Current time (MTP): ${now}`); + + if (!bestBid) + die('No proofs are mature yet, auction has not started.'); +} + +async function listFills() { + const {db, context} = await setupCLI(); + + const table = new Table({ + head: [ + 'Name', + 'Status', + 'Confirmed', + 'Lockup', + 'Price', + 'Fee', + 'Broadcast At', + 'Confirmed At', + ], + }); + + const names = []; + await db.iterateInboundNames((key, value) => { + const keySplits = key.split('/'); + const name = keySplits[keySplits.length - 1]; + const version = Number(value); + names.push([name, version]); + }); + + for (const [name, version] of names) { + const state = await db.getInboundNameState(name, version); + + switch (state) { + case 'FILL': { + const fill = new SwapFill(await db.getSwapFill(name, version)); + const confirmation = await fill.getConfirmationDetails(context); + table.push([ + fill.name, + 'FILL', + confirmation.confirmedAt ? 'YES' : 'NO', + confirmation.confirmedAt + ? confirmation.spendable + ? '0 BLOCKS' + : `${confirmation.spendableIn} BLOCKS` + : '-', + (fill.price / 1e6).toFixed(6), + (fill.fee / 1e6).toFixed(6), + format(new Date(fill.broadcastAt), 'MM/dd/yyyy HH:MM:SS'), + confirmation.confirmedAt + ? format(new Date(confirmation.confirmedAt * 1000), 'MM/dd/yyyy HH:MM:SS') + : '-', + ]); + break; + } + case 'FINALIZE': { + const fill = new SwapFill(await db.getSwapFill(name, version)); + const finalize = new SwapFinalize( + await db.getSwapFinalize(name, version), + ); + const confirmation = await fill.getConfirmationDetails(context); + table.push([ + finalize.name, + 'FINALIZE', + confirmation.confirmedAt ? 'YES' : 'NO', + '-', + (fill.price / 1e6).toFixed(6), + (fill.fee / 1e6).toFixed(6), + format(new Date(finalize.broadcastAt), 'MM/dd/yyyy HH:MM:SS'), + confirmation.confirmedAt + ? format(new Date(confirmation.confirmedAt), 'MM/dd/yyyy HH:MM:SS') + : '-', + ]); + break; + } + } + } + process.stdout.write(table.toString()); + process.stdout.write('\n'); +} + +async function backup(outFile) { + const {prefix} = program.opts(); + log(`Backing up database in ${prefix}.`); + await backupDb(prefix, outFile); + log('Done.'); +} \ No newline at end of file