diff --git a/lerna.json b/lerna.json
index 7b1ffa8ff..cf46a9187 100644
--- a/lerna.json
+++ b/lerna.json
@@ -1,5 +1,5 @@
{
- "version": "6.7.0",
+ "version": "independent",
"registry": "https://registry.npmjs.org/",
"publishConfig": {
"access": "public"
diff --git a/package-lock.json b/package-lock.json
index ba51c4ab6..bc6a3a0c3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4449,7 +4449,7 @@
"resolved": "packages/profile",
"link": true
},
- "node_modules/@stacks/sbtc": {
+ "node_modules/@stacks/sbtc-developer-release": {
"resolved": "packages/sbtc",
"link": true
},
@@ -4621,6 +4621,21 @@
"@types/node": "*"
}
},
+ "node_modules/@types/chai": {
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.6.tgz",
+ "integrity": "sha512-VOVRLM1mBxIRxydiViqPcKn6MIxZytrbMpd6RJLIWKxUNr3zux8no0Oc7kJx0WAPIitgZ0gkrDS+btlqQpubpw==",
+ "dev": true
+ },
+ "node_modules/@types/chai-subset": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.3.tgz",
+ "integrity": "sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==",
+ "dev": true,
+ "dependencies": {
+ "@types/chai": "*"
+ }
+ },
"node_modules/@types/common-tags": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/@types/common-tags/-/common-tags-1.8.1.tgz",
@@ -5189,6 +5204,101 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
+ "node_modules/@vitest/expect": {
+ "version": "0.34.6",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.34.6.tgz",
+ "integrity": "sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==",
+ "dev": true,
+ "dependencies": {
+ "@vitest/spy": "0.34.6",
+ "@vitest/utils": "0.34.6",
+ "chai": "^4.3.10"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/runner": {
+ "version": "0.34.6",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.34.6.tgz",
+ "integrity": "sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==",
+ "dev": true,
+ "dependencies": {
+ "@vitest/utils": "0.34.6",
+ "p-limit": "^4.0.0",
+ "pathe": "^1.1.1"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/runner/node_modules/p-limit": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz",
+ "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==",
+ "dev": true,
+ "dependencies": {
+ "yocto-queue": "^1.0.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@vitest/runner/node_modules/yocto-queue": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz",
+ "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@vitest/snapshot": {
+ "version": "0.34.6",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.34.6.tgz",
+ "integrity": "sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==",
+ "dev": true,
+ "dependencies": {
+ "magic-string": "^0.30.1",
+ "pathe": "^1.1.1",
+ "pretty-format": "^29.5.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/spy": {
+ "version": "0.34.6",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.6.tgz",
+ "integrity": "sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==",
+ "dev": true,
+ "dependencies": {
+ "tinyspy": "^2.1.1"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/utils": {
+ "version": "0.34.6",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.6.tgz",
+ "integrity": "sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==",
+ "dev": true,
+ "dependencies": {
+ "diff-sequences": "^29.4.3",
+ "loupe": "^2.3.6",
+ "pretty-format": "^29.5.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
"node_modules/@webassemblyjs/ast": {
"version": "1.11.6",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz",
@@ -5910,6 +6020,15 @@
"node": ">=0.8"
}
},
+ "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==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/ast-module-types": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/ast-module-types/-/ast-module-types-4.0.0.tgz",
@@ -6775,6 +6894,15 @@
"node": ">=8"
}
},
+ "node_modules/cac": {
+ "version": "6.7.14",
+ "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
+ "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/cacache": {
"version": "17.1.3",
"resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.3.tgz",
@@ -6937,6 +7065,24 @@
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="
},
+ "node_modules/chai": {
+ "version": "4.3.10",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz",
+ "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==",
+ "dev": 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.0.8"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
@@ -6964,6 +7110,18 @@
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="
},
+ "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==",
+ "dev": true,
+ "dependencies": {
+ "get-func-name": "^2.0.2"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/cheerio": {
"version": "0.22.0",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz",
@@ -8484,6 +8642,18 @@
}
}
},
+ "node_modules/deep-eql": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
+ "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==",
+ "dev": true,
+ "dependencies": {
+ "type-detect": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/deep-extend": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
@@ -10913,6 +11083,15 @@
"node": "6.* || 8.* || >= 10.*"
}
},
+ "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==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/get-intrinsic": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
@@ -15861,6 +16040,18 @@
"node": ">=8.9.0"
}
},
+ "node_modules/local-pkg": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz",
+ "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==",
+ "dev": true,
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
"node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -16111,6 +16302,15 @@
"triple-beam": "^1.3.0"
}
},
+ "node_modules/loupe": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz",
+ "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==",
+ "dev": true,
+ "dependencies": {
+ "get-func-name": "^2.0.0"
+ }
+ },
"node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -16244,6 +16444,18 @@
"node": ">=8"
}
},
+ "node_modules/magic-string": {
+ "version": "0.30.4",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.4.tgz",
+ "integrity": "sha512-Q/TKtsC5BPm0kGqgBIF9oXAs/xEf2vRKiIB4wCRQTJOQIByZ1d+NnUOotvJOvNpi5RNIgVOMC3pOuaP1ZTDlVg==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.4.15"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/make-dir": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
@@ -16924,6 +17136,18 @@
"node": ">=10"
}
},
+ "node_modules/mlly": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.2.tgz",
+ "integrity": "sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^8.10.0",
+ "pathe": "^1.1.1",
+ "pkg-types": "^1.0.3",
+ "ufo": "^1.3.0"
+ }
+ },
"node_modules/modify-values": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz",
@@ -18674,6 +18898,21 @@
"node": ">=8"
}
},
+ "node_modules/pathe": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.1.tgz",
+ "integrity": "sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==",
+ "dev": true
+ },
+ "node_modules/pathval": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
+ "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/pbkdf2": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
@@ -18783,6 +19022,17 @@
"node": ">=8"
}
},
+ "node_modules/pkg-types": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz",
+ "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==",
+ "dev": true,
+ "dependencies": {
+ "jsonc-parser": "^3.2.0",
+ "mlly": "^1.2.0",
+ "pathe": "^1.1.0"
+ }
+ },
"node_modules/pluralize": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz",
@@ -20291,6 +20541,22 @@
"node": ">=8"
}
},
+ "node_modules/rollup": {
+ "version": "3.29.4",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
+ "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==",
+ "dev": true,
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=14.18.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
"node_modules/run-applescript": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz",
@@ -20668,6 +20934,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/siginfo": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
+ "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
+ "dev": true
+ },
"node_modules/signal-exit": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
@@ -21219,6 +21491,12 @@
"node": ">=8"
}
},
+ "node_modules/stackback": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
+ "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
+ "dev": true
+ },
"node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
@@ -21227,6 +21505,12 @@
"node": ">= 0.8"
}
},
+ "node_modules/std-env": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.4.3.tgz",
+ "integrity": "sha512-f9aPhy8fYBuMN+sNfakZV18U39PbalgjXG3lLB9WkaYTxijru61wb57V9wxxNthXM5Sd88ETBWi29qLAsHO52Q==",
+ "dev": true
+ },
"node_modules/stream-browserify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz",
@@ -21458,6 +21742,18 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/strip-literal": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.3.0.tgz",
+ "integrity": "sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^8.10.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
"node_modules/strong-log-transformer": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz",
@@ -21810,6 +22106,30 @@
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
},
+ "node_modules/tinybench": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.1.tgz",
+ "integrity": "sha512-65NKvSuAVDP/n4CqH+a9w2kTlLReS9vhsAP06MWx+/89nMinJyB2icyl58RIcqCmIggpojIGeuJGhjU1aGMBSg==",
+ "dev": true
+ },
+ "node_modules/tinypool": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.7.0.tgz",
+ "integrity": "sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==",
+ "dev": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/tinyspy": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.1.1.tgz",
+ "integrity": "sha512-XPJL2uSzcOyBMky6OFrusqWlzfFrXtE0hPuMgW8A2HmaqrPo4ZQHRN/V0QXN3FSjKxpsbRrFc5LI7KOwBsT1/w==",
+ "dev": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
"node_modules/titleize": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz",
@@ -22420,6 +22740,12 @@
"node": ">=14.17"
}
},
+ "node_modules/ufo": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.1.tgz",
+ "integrity": "sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw==",
+ "dev": true
+ },
"node_modules/uglify-js": {
"version": "3.17.4",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz",
@@ -22683,57 +23009,601 @@
"extsprintf": "^1.2.0"
}
},
- "node_modules/vscode-oniguruma": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz",
- "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==",
- "dev": true
- },
- "node_modules/vscode-textmate": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz",
- "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==",
- "dev": true
- },
- "node_modules/w3c-hr-time": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
- "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==",
- "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.",
+ "node_modules/vite": {
+ "version": "4.4.9",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz",
+ "integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==",
"dev": true,
"dependencies": {
- "browser-process-hrtime": "^1.0.0"
+ "esbuild": "^0.18.10",
+ "postcss": "^8.4.27",
+ "rollup": "^3.27.1"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ },
+ "peerDependencies": {
+ "@types/node": ">= 14",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ }
}
},
- "node_modules/w3c-xmlserializer": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz",
- "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==",
+ "node_modules/vite-node": {
+ "version": "0.34.6",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.34.6.tgz",
+ "integrity": "sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==",
"dev": true,
"dependencies": {
- "xml-name-validator": "^3.0.0"
+ "cac": "^6.7.14",
+ "debug": "^4.3.4",
+ "mlly": "^1.4.0",
+ "pathe": "^1.1.1",
+ "picocolors": "^1.0.0",
+ "vite": "^3.0.0 || ^4.0.0 || ^5.0.0-0"
+ },
+ "bin": {
+ "vite-node": "vite-node.mjs"
},
"engines": {
- "node": ">=10"
+ "node": ">=v14.18.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
}
},
- "node_modules/walkdir": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.4.1.tgz",
- "integrity": "sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ==",
+ "node_modules/vite/node_modules/@esbuild/android-arm": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz",
+ "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==",
+ "cpu": [
+ "arm"
+ ],
"dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
"engines": {
- "node": ">=6.0.0"
+ "node": ">=12"
}
},
- "node_modules/walker": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",
- "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==",
+ "node_modules/vite/node_modules/@esbuild/android-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz",
+ "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==",
+ "cpu": [
+ "arm64"
+ ],
"dev": true,
- "dependencies": {
- "makeerror": "1.0.12"
- }
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/android-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz",
+ "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/darwin-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz",
+ "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/darwin-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz",
+ "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz",
+ "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/freebsd-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz",
+ "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-arm": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz",
+ "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz",
+ "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-ia32": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz",
+ "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-loong64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz",
+ "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-mips64el": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz",
+ "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-ppc64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz",
+ "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-riscv64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz",
+ "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-s390x": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz",
+ "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz",
+ "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/netbsd-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz",
+ "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/openbsd-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz",
+ "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/sunos-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz",
+ "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/win32-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz",
+ "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/win32-ia32": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz",
+ "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/win32-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz",
+ "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/esbuild": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz",
+ "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/android-arm": "0.18.20",
+ "@esbuild/android-arm64": "0.18.20",
+ "@esbuild/android-x64": "0.18.20",
+ "@esbuild/darwin-arm64": "0.18.20",
+ "@esbuild/darwin-x64": "0.18.20",
+ "@esbuild/freebsd-arm64": "0.18.20",
+ "@esbuild/freebsd-x64": "0.18.20",
+ "@esbuild/linux-arm": "0.18.20",
+ "@esbuild/linux-arm64": "0.18.20",
+ "@esbuild/linux-ia32": "0.18.20",
+ "@esbuild/linux-loong64": "0.18.20",
+ "@esbuild/linux-mips64el": "0.18.20",
+ "@esbuild/linux-ppc64": "0.18.20",
+ "@esbuild/linux-riscv64": "0.18.20",
+ "@esbuild/linux-s390x": "0.18.20",
+ "@esbuild/linux-x64": "0.18.20",
+ "@esbuild/netbsd-x64": "0.18.20",
+ "@esbuild/openbsd-x64": "0.18.20",
+ "@esbuild/sunos-x64": "0.18.20",
+ "@esbuild/win32-arm64": "0.18.20",
+ "@esbuild/win32-ia32": "0.18.20",
+ "@esbuild/win32-x64": "0.18.20"
+ }
+ },
+ "node_modules/vitest": {
+ "version": "0.34.6",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.34.6.tgz",
+ "integrity": "sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==",
+ "dev": true,
+ "dependencies": {
+ "@types/chai": "^4.3.5",
+ "@types/chai-subset": "^1.3.3",
+ "@types/node": "*",
+ "@vitest/expect": "0.34.6",
+ "@vitest/runner": "0.34.6",
+ "@vitest/snapshot": "0.34.6",
+ "@vitest/spy": "0.34.6",
+ "@vitest/utils": "0.34.6",
+ "acorn": "^8.9.0",
+ "acorn-walk": "^8.2.0",
+ "cac": "^6.7.14",
+ "chai": "^4.3.10",
+ "debug": "^4.3.4",
+ "local-pkg": "^0.4.3",
+ "magic-string": "^0.30.1",
+ "pathe": "^1.1.1",
+ "picocolors": "^1.0.0",
+ "std-env": "^3.3.3",
+ "strip-literal": "^1.0.1",
+ "tinybench": "^2.5.0",
+ "tinypool": "^0.7.0",
+ "vite": "^3.1.0 || ^4.0.0 || ^5.0.0-0",
+ "vite-node": "0.34.6",
+ "why-is-node-running": "^2.2.2"
+ },
+ "bin": {
+ "vitest": "vitest.mjs"
+ },
+ "engines": {
+ "node": ">=v14.18.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "@edge-runtime/vm": "*",
+ "@vitest/browser": "*",
+ "@vitest/ui": "*",
+ "happy-dom": "*",
+ "jsdom": "*",
+ "playwright": "*",
+ "safaridriver": "*",
+ "webdriverio": "*"
+ },
+ "peerDependenciesMeta": {
+ "@edge-runtime/vm": {
+ "optional": true
+ },
+ "@vitest/browser": {
+ "optional": true
+ },
+ "@vitest/ui": {
+ "optional": true
+ },
+ "happy-dom": {
+ "optional": true
+ },
+ "jsdom": {
+ "optional": true
+ },
+ "playwright": {
+ "optional": true
+ },
+ "safaridriver": {
+ "optional": true
+ },
+ "webdriverio": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vscode-oniguruma": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz",
+ "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==",
+ "dev": true
+ },
+ "node_modules/vscode-textmate": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz",
+ "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==",
+ "dev": true
+ },
+ "node_modules/w3c-hr-time": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
+ "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==",
+ "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.",
+ "dev": true,
+ "dependencies": {
+ "browser-process-hrtime": "^1.0.0"
+ }
+ },
+ "node_modules/w3c-xmlserializer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz",
+ "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==",
+ "dev": true,
+ "dependencies": {
+ "xml-name-validator": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/walkdir": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.4.1.tgz",
+ "integrity": "sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/walker": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",
+ "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==",
+ "dev": true,
+ "dependencies": {
+ "makeerror": "1.0.12"
+ }
},
"node_modules/watchpack": {
"version": "2.4.0",
@@ -23122,6 +23992,22 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/why-is-node-running": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz",
+ "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==",
+ "dev": true,
+ "dependencies": {
+ "siginfo": "^2.0.0",
+ "stackback": "0.0.2"
+ },
+ "bin": {
+ "why-is-node-running": "cli.js"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/wide-align": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
@@ -23954,21 +24840,37 @@
}
},
"packages/sbtc": {
- "name": "@stacks/sbtc",
- "version": "6.7.0",
+ "name": "@stacks/sbtc-developer-release",
+ "version": "0.1.0",
"license": "MIT",
"dependencies": {
"@noble/secp256k1": "^2.0.0",
"@scure/base": "^1.1.3",
"@scure/btc-signer": "^1.1.0",
+ "@stacks/common": "^6.7.0",
"@stacks/encryption": "^6.7.0",
"@stacks/transactions": "^6.7.0",
"c32check": "^2.0.0",
"micro-packed": "^0.3.2"
},
"devDependencies": {
+ "@scure/bip32": "^1.3.2",
+ "@scure/bip39": "^1.2.1",
"jest-fetch-mock": "^3.0.3",
- "rimraf": "^3.0.2"
+ "rimraf": "^3.0.2",
+ "vitest": "^0.34.6"
+ }
+ },
+ "packages/sbtc/node_modules/@noble/hashes": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz",
+ "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 16"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
}
},
"packages/sbtc/node_modules/@noble/secp256k1": {
@@ -23990,6 +24892,47 @@
"url": "https://paulmillr.com/funding/"
}
},
+ "packages/sbtc/node_modules/@scure/bip32": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.2.tgz",
+ "integrity": "sha512-N1ZhksgwD3OBlwTv3R6KFEcPojl/W4ElJOeCZdi+vuI5QmTFwLq3OFf2zd2ROpKvxFdgZ6hUpb0dx9bVNEwYCA==",
+ "dev": true,
+ "dependencies": {
+ "@noble/curves": "~1.2.0",
+ "@noble/hashes": "~1.3.2",
+ "@scure/base": "~1.1.2"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "packages/sbtc/node_modules/@scure/bip39": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz",
+ "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==",
+ "dev": true,
+ "dependencies": {
+ "@noble/hashes": "~1.3.0",
+ "@scure/base": "~1.1.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "packages/sbtc/node_modules/@stacks/common": {
+ "version": "6.8.1",
+ "resolved": "https://registry.npmjs.org/@stacks/common/-/common-6.8.1.tgz",
+ "integrity": "sha512-ewL9GLZNQYa5a/3K4xSHlHIgHkD4rwWW/QEaPId8zQIaL+1O9qCaF4LX9orNQeOmEk8kvG0x2xGV54fXKCZeWQ==",
+ "dependencies": {
+ "@types/bn.js": "^5.1.0",
+ "@types/node": "^18.0.4"
+ }
+ },
+ "packages/sbtc/node_modules/@types/node": {
+ "version": "18.18.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.1.tgz",
+ "integrity": "sha512-3G42sxmm0fF2+Vtb9TJQpnjmP+uKlWvFa8KoEGquh4gqRmoUG/N0ufuhikw6HEsdG2G2oIKhog1GCTfz9v5NdQ=="
+ },
"packages/sbtc/node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
diff --git a/packages/sbtc/README.md b/packages/sbtc/README.md
index 112d912fe..e50464f39 100644
--- a/packages/sbtc/README.md
+++ b/packages/sbtc/README.md
@@ -1,667 +1 @@
-# @stacks/stacking [![npm](https://img.shields.io/npm/v/@stacks/stacking?color=red)](https://www.npmjs.com/package/@stacks/stacking)
-
-Library for PoX Stacking.
-
-> **Note**: [Not all methods](https://stacks.js.org/classes/_stacks_stacking.StackingClient#:~:text=methods%20-%20pox-2) are available before the 2.1 fork. These will throw if used on a <2.1 chain.
-
-## Installation
-
-```shell
-npm install @stacks/stacking
-```
-
-- [Initialization](#initialization)
-- [Stack STX](#stack-stx)
- - [Check stacking eligibility](#check-stacking-eligibility)
- - [Broadcast the stacking transaction](#broadcast-the-stacking-transaction)
- - [Extend stacking](#extend-stacking)
- - [Increase amount stacked](#increase-amount-stacked)
-- [Client helpers](#client-helpers)
- - [Will Stacking be executed in the next cycle?](#will-stacking-be-executed-in-the-next-cycle)
- - [How long (in seconds) is a Stacking cycle?](#how-long-in-seconds-is-a-stacking-cycle)
- - [How much estimated time is left (in seconds) to submit a stacking transaction for the upcoming reward cycle?](#how-much-estimated-time-is-left-in-seconds-to-submit-a-stacking-transaction-for-the-upcoming-reward-cycle)
- - [Does account have sufficient STX to meet minimum threshold?](#does-account-have-sufficient-stx-to-meet-minimum-threshold)
- - [Get PoX info](#get-pox-info)
- - [Get Stacks node info](#get-stacks-node-info)
- - [Get account balance](#get-account-balance)
- - [Get account balance locked](#get-account-balance-locked)
- - [Get account balances (from API)](#get-account-balances-from-api)
- - [Get account stacking status](#get-account-stacking-status)
- - [Get PoX operation info (current period and PoX contract versions)](#get-pox-operation-info-current-period-and-pox-contract-versions)
-- [Delegated stacking](#delegated-stacking)
- - [Stacking in a pool](#stacking-in-a-pool)
- - [Delegate STX](#delegate-stx)
- - [Revoke delegation](#revoke-delegation)
- - [Operating a pool / Stacking for others](#operating-a-pool--stacking-for-others)
- - [Stack delegated STX](#stack-delegated-stx)
- - [Extend delegated STX](#extend-delegated-stx)
- - [Increase delegated STX](#increase-delegated-stx)
- - [Commit to stacking](#commit-to-stacking)
- - [Increase existing commitment](#increase-existing-commitment)
- - [Pool helpers](#pool-helpers)
- - [Get burnchain rewards](#get-burnchain-rewards)
- - [Get burnchain rewards total](#get-burnchain-rewards-total)
- - [Get burnchain reward holders](#get-burnchain-reward-holders)
- - [Get reward set by index](#get-reward-set-by-index)
-
-## Initialization
-
-Initialize a `StackingClient` to interact with the Stacking contract.
-
-> **Note:** The `StackingClient` sets its transactions `AnchorMode` to `Any` by default.
-
-```typescript
-import { StacksTestnet, StacksMainnet } from '@stacks/network';
-import { StackingClient } from '@stacks/stacking';
-
-// for mainnet: const network = new StacksMainnet();
-const network = new StacksTestnet();
-// the stacks STX address
-const address = 'ST3XKKN4RPV69NN1PHFDNX3TYKXT7XPC4N8KC1ARH';
-const client = new StackingClient(address, network);
-```
-
-## Stack STX
-
-### Check stacking eligibility
-
-```typescript
-// a BTC address for reward payouts
-const poxAddress = 'mvuYDknzDtPgGqm2GnbAbmGMLwiyW3AwFP';
-// number cycles to stack
-const cycles = 3;
-
-// Refer to initialization section to create client instance
-const stackingEligibility = await client.canStack({ poxAddress, cycles });
-
-// {
-// eligible: false,
-// reason: 'ERR_STACKING_INVALID_LOCK_PERIOD',
-// }
-```
-
-### Broadcast the stacking transaction
-
-```typescript
-// a BTC address for reward payouts
-const poxAddress = 'mvuYDknzDtPgGqm2GnbAbmGMLwiyW3AwFP';
-// number cycles to stack
-const cycles = 3;
-// how much to stack, in microSTX
-const amountMicroStx = 100000000000n;
-// private key for transaction signing
-const privateKey = 'd48f215481c16cbe6426f8e557df9b78895661971d71735126545abddcd5377001';
-// block height at which to stack
-const burnBlockHeight = 2000;
-
-// Refer to initialization section to create client instance
-const stackingResults = await client.stack({
- amountMicroStx,
- poxAddress,
- cycles,
- privateKey,
- burnBlockHeight,
-});
-
-// {
-// txid: '0xf6e9dbf6a26c1b73a14738606cb2232375d1b440246e6bbc14a45b3a66618481',
-// }
-```
-
-### Extend stacking
-
-Extends previously stacked funds without cooldown.
-
-```typescript
-// number cycles to extend stacking by
-const extendCycles = 3;
-// a BTC address for reward payouts
-const poxAddress = 'mvuYDknzDtPgGqm2GnbAbmGMLwiyW3AwFP';
-// private key for transaction signing
-const privateKey = 'd48f215481c16cbe6426f8e557df9b78895661971d71735126545abddcd5377001';
-
-const extendResults = await client.stackExtend({
- extendCycles,
- poxAddress,
- privateKey,
-});
-
-// {
-// txid: '0xf6e9dbf6a26c1b73a14738606cb2232375d1b440246e6bbc14a45b3a66618481',
-// }
-```
-
-### Increase amount stacked
-
-Increases the amount of funds stacked/locked after previously stacking.
-
-```typescript
-// how much to increase by, in microSTX
-const increaseBy = 3000000;
-// private key for transaction signing
-const privateKey = 'd48f215481c16cbe6426f8e557df9b78895661971d71735126545abddcd5377001';
-
-const increaseResults = await client.stackIncrease({
- increaseBy,
- privateKey,
-});
-
-// {
-// txid: '0xf6e9dbf6a26c1b73a14738606cb2232375d1b440246e6bbc14a45b3a66618481',
-// }
-```
-
-## Client helpers
-
-### Will Stacking be executed in the next cycle?
-
-```typescript
-const stackingEnabledNextCycle = await client.isStackingEnabledNextCycle();
-
-// true / false
-```
-
-### How long (in seconds) is a Stacking cycle?
-
-```typescript
-const cycleDuration = await client.getCycleDuration();
-
-// 120
-```
-
-### How much estimated time is left (in seconds) to submit a stacking transaction for the upcoming reward cycle?
-
-```typescript
-const seconds = await client.getSecondsUntilStackingDeadline();
-
-// 600000
-```
-
-### Does account have sufficient STX to meet minimum threshold?
-
-```typescript
-const hasMinStxAmount = await client.hasMinimumStx();
-
-// true / false
-```
-
-### Get PoX info
-
-```typescript
-const poxInfo = await client.getPoxInfo();
-
-// {
-// contract_id: 'ST000000000000000000002AMW42H.pox',
-// first_burnchain_block_height: 0,
-// min_amount_ustx: 83335083333333,
-// prepare_cycle_length: 30,
-// rejection_fraction: 3333333333333333,
-// reward_cycle_id: 17,
-// reward_cycle_length: 120,
-// rejection_votes_left_required: 0,
-// total_liquid_supply_ustx: 40000840000000000
-// }
-```
-
-### Get Stacks node info
-
-```typescript
-const coreInfo = await client.getCoreInfo();
-
-// {
-// peer_version: 385875968,
-// pox_consensus: 'bb88a6e6e65fa7c974d3f6e91a941d05cc3dff8e',
-// burn_block_height: 2133,
-// stable_pox_consensus: '2284451c3e623237def1f8caed1c11fa46b6f0cc',
-// stable_burn_block_height: 2132,
-// server_version: 'blockstack-core 0.0.1 => 23.0.0.0 (HEAD:a4deb7a+, release build, linux [x86_64])',
-// network_id: 2147483648,
-// parent_network_id: 3669344250,
-// stacks_tip_height: 1797,
-// stacks_tip: '016df36c6a154cb6114c469a28cc0ce8b415a7af0527f13f15e66e27aa480f94',
-// stacks_tip_consensus_hash: 'bb88a6e6e65fa7c974d3f6e91a941d05cc3dff8e',
-// unanchored_tip: '6b93d2c62fc07cf44302d4928211944d2debf476e5c71fb725fb298a037323cc',
-// exit_at_block_height: null
-// }
-```
-
-### Get account balance
-
-```typescript
-const responseBalanceInfo = await client.getAccountBalance();
-
-// 800000000000
-```
-
-### Get account balance locked
-
-```typescript
-const responseBalanceLockedInfo = await client.getAccountBalanceLocked();
-
-// 40000000000
-```
-
-### Get account balances (from API)
-
-```typescript
-const responseBalancesInfo = await client.getAccountExtendedBalances();
-
-// {
-// stx: {
-// balance: '1000000',
-// total_sent: '0',
-// total_received: '1000000',
-// lock_tx_id: '0xec94e7d20af8979b44d17a0520c126bf742b999a0fc7ddbcbe0ab21b228ecc8c',
-// locked: '50000',
-// lock_height: 100,
-// burnchain_lock_height: 100,
-// burnchain_unlock_height: 200,
-// },
-// fungible_tokens: {},
-// non_fungible_tokens: {},
-// }
-```
-
-### Get account stacking status
-
-```typescript
-const stackingStatus = await client.getStatus();
-
-// {
-// stacked: true,
-// details: {
-// first_reward_cycle: 18,
-// lock_period: 10,
-// unlock_height: 3020,
-// pox_address: {
-// version: '00',
-// hashbytes: '05cf52a44bf3e6829b4f8c221cc675355bf83b7d'
-// }
-// }
-// }
-```
-
-### Get PoX operation info (current period and PoX contract versions)
-
-```typescript
-const poxOperationInfo = await client.getPoxOperationInfo();
-
-// {
-// period: 'Period3',
-// pox1: {
-// contract_id: 'ST000000000000000000002AMW42H.pox',
-// activation_burnchain_block_height: 0,
-// first_reward_cycle_id: 0,
-// },
-// pox2: {
-// contract_id: 'ST000000000000000000002AMW42H.pox-2',
-// activation_burnchain_block_height: 120,
-// first_reward_cycle_id: 25,
-// },
-// }
-```
-
-## Delegated stacking
-
-These are the methods for creating the required transactions for delegated stacking:
-
-- [Stacking in a pool](#stacking-in-a-pool)
- - [`.delegateStx` Delegate STX](#delegate-stx)
- - [`.revokeDelegateStx` Revoke delegation](#revoke-delegation)
-- [Operating a pool](#operating-a-pool)
- - [`.delegateStackStx` Stack delegated STX](#stack-delegated-stx)
- - [`.stackAggregationCommit` Commit to stacking](#commit-to-stacking)
-
-```mermaid
-sequenceDiagram
- User->>Stacks Blockchain: tx: `delegateStx`
Delegate funds to pool,
by pool's STX address
- Stacks Blockchain-->Pool Operator: Monitored by
- Pool Operator->>Stacks Blockchain: tx: `delegateStackStx`
Lock delegated funds
- Pool Operator->>Stacks Blockchain: tx: `stackAggregationCommit`
Commit stacking for each cycle
-```
-
-### Stacking in a pool
-
-If you are the account owner ("stacker"), you can delegate or revoke delegation rights.
-
-#### Delegate STX
-
-```typescript
-// STX address of the pool/pool
-const delegateTo = 'ST2MCYPWTFMD2MGR5YY695EJG0G1R4J2BTJPRGM7H';
-// burn height at which the delegation relationship should be revoked (optional)
-const untilBurnBlockHeight = 5000;
-// how much to stack, in microSTX
-const amountMicroStx = 100000000000n;
-// private key for transaction signing
-const privateKey = 'd48f215481c16cbe6426f8e557df9b78895661971d71735126545abddcd5377001';
-
-const delegetateResponse = await client.delegateStx({
- amountMicroStx,
- delegateTo,
- untilBurnBlockHeight, // optional
- privateKey,
-});
-
-// {
-// txid: '0xf6e9dbf6a26c1b73a14738606cb2232375d1b440246e6bbc14a45b3a66618481',
-// }
-```
-
-#### Revoke delegation
-
-```typescript
-// private key for transaction signing
-const privateKey = 'd48f215481c16cbe6426f8e557df9b78895661971d71735126545abddcd5377001';
-
-const revokeResponse = await client.revokeDelegateStx(privateKey);
-
-// {
-// txid: '0xf6e9dbf6a26c1b73a14738606cb2232375d1b440246e6bbc14a45b3a66618481',
-// }
-```
-
-### Operating a pool / Stacking for others
-
-If you are a pool operator (or wish to stack with someone else's funds), you can stack ("lock up") tokens for your users and commit to stacking participation for upcoming reward cycles.
-These users need to first "delegate" some or all of their funds to you (the "delegator").
-The following examples refer to the "delegator" as pool, but in practice a delegator can also stack for only single or few individuals.
-Even a group of friends could stack together and share a multi-sig BTC wallet for payouts.
-
-#### Stack delegated STX
-
-Stack STX, which have been previously delegated to the pool.
-This step only locks the funds (partial stacking).
-The pool operator will also need to ["commit"](#commit-to-stacking) to a reward cycle.
-
-```typescript
-import { getNonce } from '@stacks/transactions';
-import { StacksTestnet, StacksMainnet } from '@stacks/network';
-import { StackingClient } from '@stacks/stacking';
-
-// for mainnet: const network = new StacksMainnet();
-const network = new StacksTestnet();
-// the stacks STX address
-const address = 'ST3XKKN4RPV69NN1PHFDNX3TYKXT7XPC4N8KC1ARH';
-// pools would initiate a different client
-const poolAddress = 'ST22X605P0QX2BJC3NXEENXDPFCNJPHE02DTX5V74';
-// pool private key for transaction signing
-const poolPrivateKey = 'd48f215481c16cbe6426f8e557df9b78895661971d71735126545abddcd5377001';
-// the BTC address for reward payouts
-const poolBtcAddress = 'msiYwJCvXEzjgq6hDwD9ueBka6MTfN962Z';
-// how much to stack, in microSTX
-const amountMicroStx = 100000000000n;
-// block height at which to stack
-const burnBlockHeight = 2000;
-// number cycles to stack
-const cycles = 3;
-// if you call this method multiple times in the same block, you need to increase the nonce manually
-let nonce = await getNonce(poolAddress, network);
-nonce = nonce + 1n;
-
-const poolClient = new StackingClient(poolAddress, network);
-
-const delegetateStackResponses = await poolClient.delegateStackStx({
- stacker: address,
- amountMicroStx,
- poxAddress: poolBtcAddress,
- burnBlockHeight,
- cycles,
- privateKey: poolPrivateKey,
- nonce, // optional
-});
-
-// {
-// txid: '0xf6e9dbf6a26c1b73a14738606cb2232375d1b440246e6bbc14a45b3a66618481',
-// }
-```
-
-#### Extend delegated STX
-
-Extend stacking of STX previously delegated to the pool.
-
-```typescript
-import { getNonce } from '@stacks/transactions';
-import { StacksTestnet, StacksMainnet } from '@stacks/network';
-import { StackingClient } from '@stacks/stacking';
-
-// for mainnet: const network = new StacksMainnet();
-const network = new StacksTestnet();
-// the stacks STX address
-const address = 'ST3XKKN4RPV69NN1PHFDNX3TYKXT7XPC4N8KC1ARH';
-// pools would initiate a different client
-const poolAddress = 'ST22X605P0QX2BJC3NXEENXDPFCNJPHE02DTX5V74';
-// pool private key for transaction signing
-const poolPrivateKey = 'd48f215481c16cbe6426f8e557df9b78895661971d71735126545abddcd5377001';
-// the BTC address for reward payouts
-const poolBtcAddress = 'msiYwJCvXEzjgq6hDwD9ueBka6MTfN962Z';
-// number of cycles to extend by
-const extendCount = 3;
-// if you call this method multiple times in the same block, you need to increase the nonce manually
-let nonce = await getNonce(poolAddress, network);
-nonce = nonce + 1n;
-
-const poolClient = new StackingClient(poolAddress, network);
-
-const delegetateExtendResponses = await poolClient.delegateStackExtend({
- extendCount,
- stacker: address,
- poxAddress: poolBtcAddress,
- privateKey: poolPrivateKey,
- nonce, // optional
-});
-
-// {
-// txid: '0xf6e9dbf6a26c1b73a14738606cb2232375d1b440246e6bbc14a45b3a66618481',
-// }
-```
-
-#### Increase delegated STX
-
-Increase the locked amount of delegated STX stacked.
-
-```typescript
-import { getNonce } from '@stacks/transactions';
-import { StacksTestnet, StacksMainnet } from '@stacks/network';
-import { StackingClient } from '@stacks/stacking';
-
-// for mainnet: const network = new StacksMainnet();
-const network = new StacksTestnet();
-// the stacks STX address
-const address = 'ST3XKKN4RPV69NN1PHFDNX3TYKXT7XPC4N8KC1ARH';
-// pools would initiate a different client
-const poolAddress = 'ST22X605P0QX2BJC3NXEENXDPFCNJPHE02DTX5V74';
-// pool private key for transaction signing
-const poolPrivateKey = 'd48f215481c16cbe6426f8e557df9b78895661971d71735126545abddcd5377001';
-// the BTC address for reward payouts
-const poolBtcAddress = 'msiYwJCvXEzjgq6hDwD9ueBka6MTfN962Z';
-// amount to increase by, in microSTX
-const increaseBy = 3;
-// if you call this method multiple times in the same block, you need to increase the nonce manually
-let nonce = await getNonce(poolAddress, network);
-nonce = nonce + 1n;
-
-const poolClient = new StackingClient(poolAddress, network);
-
-const delegetateIncreaseResponses = await poolClient.delegateStackIncrease({
- increaseBy,
- stacker: address,
- poxAddress: poolBtcAddress,
- privateKey: poolPrivateKey,
- nonce, // optional
-});
-
-// {
-// txid: '0xf6e9dbf6a26c1b73a14738606cb2232375d1b440246e6bbc14a45b3a66618481',
-// }
-```
-
-#### Commit to stacking
-
-The result of this commit transaction will contain the index of the pools reward set entry.
-
-```typescript
-// reward cycle id to commit to
-const rewardCycle = 12;
-// the BTC address for reward payouts
-const poolBtcAddress = 'msiYwJCvXEzjgq6hDwD9ueBka6MTfN962Z';
-// Private key
-const privateKeyDelegate = 'd48f215481c16cbe6426f8e557df9b78895661971d71735126545abddcd5377001';
-
-const delegetateCommitResponse = await poolClient.stackAggregationCommitIndexed({
- rewardCycle,
- poxAddress: poolBtcAddress,
- privateKey: privateKeyDelegate,
-});
-
-// {
-// txid: '0xf6e9dbf6a26c1b73a14738606cb2232375d1b440246e6bbc14a45b3a66618481',
-// }
-```
-
-#### Increase existing commitment
-
-The result of this commit transaction will contain the index of the pools reward set entry.
-
-```typescript
-// reward cycle id to commit to
-const rewardCycle = 12;
-// reward set entry index
-const rewardIndex = 3;
-// the BTC address for reward payouts
-const poolBtcAddress = 'msiYwJCvXEzjgq6hDwD9ueBka6MTfN962Z';
-// Private key
-const privateKeyDelegate = 'd48f215481c16cbe6426f8e557df9b78895661971d71735126545abddcd5377001';
-
-const delegetateIncreaseResponse = await poolClient.stackAggregationIncrease({
- rewardCycle,
- rewardIndex,
- poxAddress: poolBtcAddress,
- privateKey: privateKeyDelegate,
-});
-
-// {
-// txid: '0xf6e9dbf6a26c1b73a14738606cb2232375d1b440246e6bbc14a45b3a66618481',
-// }
-```
-
-#### Pool helpers
-
-##### Get burnchain rewards
-
-```typescript
-import { StacksTestnet, StacksMainnet } from '@stacks/network';
-import { StackingClient } from '@stacks/stacking';
-
-const address = 'myfTfju9XSMRusaY2qTitSEMSchsWRA441';
-// for mainnet: const network = new StacksMainnet();
-const network = new StacksTestnet();
-const client = new StackingClient(address, network);
-const options = { limit: 2, offset: 0 };
-
-const rewards = await client.getRewardsForBtcAddress(options);
-
-// {
-// limit: 2,
-// offset: 0,
-// results: [
-// {
-// canonical: true,
-// burn_block_hash: '0x000000000000002083ca8303a2262d09a824cecb34b78f13a04787e4f05441d3',
-// burn_block_height: 2004622,
-// burn_amount: '0',
-// reward_recipient: 'myfTfju9XSMRusaY2qTitSEMSchsWRA441',
-// reward_amount: '20000',
-// reward_index: 0
-// },
-// {
-// canonical: true,
-// burn_block_hash: '0x000000000000002f72213de621f9daf60d76aed3902a811561d06373b2fa6123',
-// burn_block_height: 2004621,
-// burn_amount: '0',
-// reward_recipient: 'myfTfju9XSMRusaY2qTitSEMSchsWRA441',
-// reward_amount: '20000',
-// reward_index: 0
-// }
-// ]
-// };
-```
-
-##### Get burnchain rewards total
-
-```typescript
-import { StacksTestnet, StacksMainnet } from '@stacks/network';
-import { StackingClient } from '@stacks/stacking';
-
-const address = 'myfTfju9XSMRusaY2qTitSEMSchsWRA441';
-// for mainnet: const network = new StacksMainnet();
-const network = new StacksTestnet();
-const client = new StackingClient(address, network);
-
-const total = await client.getRewardsTotalForBtcAddress();
-// {
-// reward_recipient: 'myfTfju9XSMRusaY2qTitSEMSchsWRA441',
-// reward_amount: '0'
-// }
-```
-
-##### Get burnchain reward holders
-
-```typescript
-import { StacksTestnet, StacksMainnet } from '@stacks/network';
-import { StackingClient } from '@stacks/stacking';
-
-const address = 'myfTfju9XSMRusaY2qTitSEMSchsWRA441';
-// for mainnet: const network = new StacksMainnet();
-const network = new StacksTestnet();
-const client = new StackingClient(address, network);
-const options = { limit: 2, offset: 0 };
-
-const rewardHolders = await client.getRewardHoldersForBtcAddress(options);
-// {
-// limit: 2,
-// offset: 0,
-// total: 46,
-// results: [
-// {
-// canonical: true,
-// burn_block_hash: '0x000000000000002083ca8303a2262d09a824cecb34b78f13a04787e4f05441d3',
-// burn_block_height: 2004622,
-// address: 'myfTfju9XSMRusaY2qTitSEMSchsWRA441',
-// slot_index: 1
-// },
-// {
-// canonical: true,
-// burn_block_hash: '0x000000000000002083ca8303a2262d09a824cecb34b78f13a04787e4f05441d3',
-// burn_block_height: 2004622,
-// address: 'myfTfju9XSMRusaY2qTitSEMSchsWRA441',
-// slot_index: 0
-// }
-// ]
-// };
-```
-
-##### Get reward set by index
-
-```typescript
-import { StacksTestnet, StacksMainnet } from '@stacks/network';
-import { StackingClient } from '@stacks/stacking';
-
-const address = 'myfTfju9XSMRusaY2qTitSEMSchsWRA441';
-// for mainnet: const network = new StacksMainnet();
-const network = new StacksTestnet();
-const client = new StackingClient(address, network);
-
-const rewardSetItem = await client.getRewardSet({
- rewardCyleId: 49,
- rewardSetIndex: 3,
-});
-
-// {
-// pox_address: {
-// version: 0,
-// hashbytes: [ 67, 89, 107, 83, 134, 244, 102, 134, 62, 37, 101, 141, 223, 148, 189, 15, 173, 171, 0, 72 ]
-// },
-// total_ustx: 1875230000000000
-// }
-```
+# @stacks/sbtc-developer-release
diff --git a/packages/sbtc/jest.config.js b/packages/sbtc/jest.config.js
deleted file mode 100644
index fe8e05183..000000000
--- a/packages/sbtc/jest.config.js
+++ /dev/null
@@ -1,3 +0,0 @@
-const makeJestConfig = require('../../configs/jestConfig');
-
-module.exports = makeJestConfig(__dirname);
diff --git a/packages/sbtc/package.json b/packages/sbtc/package.json
index 79b77acbd..543978784 100644
--- a/packages/sbtc/package.json
+++ b/packages/sbtc/package.json
@@ -1,6 +1,6 @@
{
- "name": "@stacks/sbtc",
- "version": "6.7.0",
+ "name": "@stacks/sbtc-developer-release",
+ "version": "0.1.0",
"description": "Library for sBTC.",
"license": "MIT",
"author": "Hiro Systems PBC (https://hiro.so)",
@@ -23,14 +23,18 @@
"@noble/secp256k1": "^2.0.0",
"@scure/base": "^1.1.3",
"@scure/btc-signer": "^1.1.0",
+ "@stacks/common": "^6.7.0",
"@stacks/encryption": "^6.7.0",
"@stacks/transactions": "^6.7.0",
"c32check": "^2.0.0",
"micro-packed": "^0.3.2"
},
"devDependencies": {
+ "@scure/bip32": "^1.3.2",
+ "@scure/bip39": "^1.2.1",
"jest-fetch-mock": "^3.0.3",
- "rimraf": "^3.0.2"
+ "rimraf": "^3.0.2",
+ "vitest": "^0.34.6"
},
"sideEffects": false,
"typings": "dist/index.d.ts",
diff --git a/packages/sbtc/src/index.ts b/packages/sbtc/src/index.ts
index 350e99d94..af47bf885 100644
--- a/packages/sbtc/src/index.ts
+++ b/packages/sbtc/src/index.ts
@@ -1,39 +1 @@
-// PLACEHOLDER FILE
-
-interface MintOptions {
- amount: number; // (amount uint)
- destination: string; // (destination principal)
- depositTxid: string; // (deposit-txid (buff 32))
- burnChainHeight: number; // (burn-chain-height uint)
- merkleProof: string[]; // (merkle-proof (list 14 (buff 32)))
- txIndex: number; // (tx-index uint)
- treeDepth: number; // (tree-depth uint)
- blockHeader: string; // (block-header (buff 80)))
-}
-
-export class sBTCClient {
- constructor(public network: StacksNetwork) {}
-
- /**
-
- */
- async mint(options: MintOptions): Promise {
- const [contractAddress, contractName] = this.parseContractId(options?.contractId);
- const result = await callReadOnlyFunction({
- network: this.network,
- senderAddress: this.address,
- contractAddress,
- contractName,
- functionArgs: [uintCV(options.rewardCyleId), uintCV(options.rewardSetIndex)],
- functionName: 'get-reward-set-pox-address',
- });
-
- return unwrapMap(result as OptionalCV, tuple => ({
- pox_address: {
- version: ((tuple.data['pox-addr'] as TupleCV).data['version'] as BufferCV).buffer,
- hashbytes: ((tuple.data['pox-addr'] as TupleCV).data['hashbytes'] as BufferCV).buffer,
- },
- total_ustx: (tuple.data['total-ustx'] as UIntCV).value,
- }));
- }
-}
+export * from './transactions';
diff --git a/packages/sbtc/src/transactions/api.ts b/packages/sbtc/src/transactions/api.ts
new file mode 100644
index 000000000..a8ef55055
--- /dev/null
+++ b/packages/sbtc/src/transactions/api.ts
@@ -0,0 +1,130 @@
+import * as btc from '@scure/btc-signer';
+import { Cl } from '@stacks/transactions';
+
+// https://blockstream.info/api/address/1KFHE7w8BhaENAswwryaoccDb6qcT6DbYY/utxo
+// [{"txid":"033e44b535c5709d30234921608219ee5ca1e320fa9def44715eaeb2b7ad52d3","vout":0,"status":{"confirmed":false},"value":42200}]
+export type BlockstreamUtxo = {
+ txid: string;
+ vout: number;
+ value: number;
+ status:
+ | {
+ confirmed: false;
+ }
+ | {
+ confirmed: true;
+ block_height: number;
+ block_hash: string;
+ block_time: number;
+ };
+};
+
+export type BlockstreamUtxoWithTxHex = BlockstreamUtxo & {
+ hex: string;
+};
+
+export async function fetchUtxos(address: string): Promise {
+ // todo: error handling?
+ return (await fetch(`https://blockstream.info/testnet/api/address/${address}/utxo`).then(res =>
+ res.json()
+ )) as BlockstreamUtxo[];
+}
+
+export async function fetchTxHex(txid: string): Promise {
+ // todo: error handling?
+ return await fetch(`https://blockstream.info/testnet/api/tx/${txid}/hex`).then(res => res.text());
+}
+
+type BlockstreamFeeEstimates = {
+ [K in
+ | '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'
+ | '144'
+ | '504'
+ | '1008']: number;
+};
+
+export async function estimateFeeRates(): Promise {
+ return await fetch(`https://blockstream.info/testnet/api/fee-estimates`).then(res => res.json());
+}
+
+export async function estimateFeeRate(target: 'low' | 'medium' | 'high' | number): Promise {
+ const feeEstimates = await estimateFeeRates();
+ const t =
+ typeof target === 'number'
+ ? target.toString()
+ : target === 'high'
+ ? '1'
+ : target === 'medium'
+ ? '2'
+ : '3';
+ if (t in feeEstimates) {
+ return feeEstimates[t as keyof BlockstreamFeeEstimates];
+ }
+
+ throw new Error(`Invalid fee target: ${target}`);
+}
+
+export async function broadcastTx(tx: btc.Transaction): Promise {
+ return await fetch(`https://blockstream.info/testnet/api/tx`, {
+ method: 'POST',
+ body: tx.hex,
+ }).then(res => res.text());
+}
+
+export async function stacksCallReadOnly({
+ contractAddress,
+ functionName,
+ sender = 'ST000000000000000000002AMW42H',
+ args = [],
+}: {
+ contractAddress: string;
+ functionName: string;
+ sender?: string;
+ args?: string[];
+}) {
+ contractAddress = contractAddress.replace('.', '/');
+ return await fetch(
+ `https://api.testnet.hiro.so/v2/contracts/call-read/${contractAddress}/${encodeURIComponent(
+ functionName
+ )}`,
+ {
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ sender, arguments: args }),
+ }
+ )
+ .then(res => res.json())
+ .then(res => Cl.deserialize(res.result));
+}
+
+// export async function informBridgeApi(txid: string) {
+// // todo
+// return 'txid';
+// }
diff --git a/packages/sbtc/src/transactions/deposit.ts b/packages/sbtc/src/transactions/deposit.ts
index 0bd68ff5a..8bceccca6 100644
--- a/packages/sbtc/src/transactions/deposit.ts
+++ b/packages/sbtc/src/transactions/deposit.ts
@@ -1,15 +1,20 @@
import * as btc from '@scure/btc-signer';
-import * as secp from '@noble/secp256k1';
-import * as P from 'micro-packed';
-import { hex } from '@scure/base';
-import type { BridgeTransactionType, UTXO } from './types/sbtc_types.js';
-import { toStorable, buildDepositPayload, buildDepositPayloadOpReturn } from './payload_utils.js';
-import { addInputs, inputAmt } from './wallet_utils.js';
-import { MagicBytes as MagicBytes, MagicBytes, OPCodes, OpCode } from './constants.js';
+import { hexToBytes, intToHex, utf8ToBytes } from '@stacks/common';
import { c32addressDecode } from 'c32check';
+import * as P from 'micro-packed';
+import * as api from './api';
+import { BlockstreamUtxo, BlockstreamUtxoWithTxHex } from './api';
+import { MagicBytes, OpCode } from './constants';
+
+// todo: move to constants?
-export const REVEAL_PAYMENT = 10001; // todo: is this const?
-export const DUST = 500; // todo: double-check what this has to be set to
+// Estimates based on https://bitcoinops.org/en/tools/calc-size/
+const OVERHEAD_TX = 4 + 1 + 1 + 4; // new btc.Transaction().vsize
+// const OVERHEAD_INPUT = 36 + 1 + 4 + 0.25;
+// const OVERHEAD_OUTPUT = 8 + 1;
+// const OVERHEAD_INPUT_P2PKH = 107;
+const VSIZE_INPUT_P2WPKH = 68;
+// const OVERHEAD_OUTPUT_P2PKH = 25;
const concat = P.concatBytes;
@@ -23,17 +28,6 @@ interface BitcoinNetwork {
export const NETWORK: BitcoinNetwork = btc.NETWORK;
export const TEST_NETWORK: BitcoinNetwork = btc.TEST_NETWORK;
-interface DepositOpts {
- network?: BitcoinNetwork;
- amount: number;
- btcFeeRates: any;
- addressInfo: any;
- stacksAddress: string;
- sbtcWalletAddress: string;
- cardinal: string;
- userPaymentPubKey: string;
-}
-
export function buildSBtcDepositBtcPayload({
network: net,
address,
@@ -42,269 +36,267 @@ export function buildSBtcDepositBtcPayload({
address: string;
}): Uint8Array {
const magicBytes =
- net.bech32 === 'tb' ? hex.decode(MagicBytes.Testnet) : hex.decode(MagicBytes.Mainnet);
- const opCodeBytes = hex.decode(OpCode.PegIn);
+ net.bech32 === 'tb' ? hexToBytes(MagicBytes.Testnet) : hexToBytes(MagicBytes.Mainnet);
+ const opCodeBytes = hexToBytes(OpCode.PegIn);
return concat(magicBytes, opCodeBytes, stacksAddressBytes(address));
}
function stacksAddressBytes(address: string): Uint8Array {
const [addr, contractName] = address.split('.');
const [version, hash] = c32addressDecode(addr);
- const versionBytes = hex.decode(version.toString(16));
- const hashBytes = hex.decode(hash);
+ const versionBytes = hexToBytes(version.toString(16));
+ const hashBytes = hexToBytes(hash);
+ const contractNameBytes = lengthPrefixedString(contractName, utf8ToBytes);
- return concat(versionBytes, hashBytes, lpContractNameBytes(contractName));
+ return concat(versionBytes, hashBytes, contractNameBytes);
}
-function lpContractNameBytes(contractName?: string): Uint8Array {
- if (!contractName) return Uint8Array.from([0]); // empty
+// todo: move to utils somewhere
+function lengthPrefixedString(
+ something: string | null | undefined,
+ map: (something: string) => Uint8Array = utf8ToBytes,
+ maxByteLength: number = 40,
+ prefixByteLength: number = 1
+): Uint8Array {
+ if (!something) return Uint8Array.from([0]); // empty or nullish (optional)
+
+ const bytes = map(something);
+ if (maxByteLength >= 0 && bytes.byteLength > maxByteLength)
+ throw new RangeError(`Content byteLength exceeds maximum length of ${maxByteLength}`);
- const cnameBuf = new TextEncoder().encode(contractName);
- const cnameLen = cnameBuf.byteLength;
- if (cnameBuf.length > 40) throw new Error('Contract name is too long - max 40 characters');
- return concat(cnameLen, cnameBuf);
+ const prefixBytes = hexToBytes(intToHex(bytes.byteLength, prefixByteLength));
+ if (prefixBytes.byteLength > prefixByteLength)
+ throw new RangeError(`Prefix byteLength exceeds maximum length of ${prefixByteLength}`);
+
+ return concat(prefixBytes, bytes);
}
-function optionalLengthPrefixed(
- something: T | null | undefined,
- fn: (something: T) => Uint8Array,
- maxLength?: number = -1
-): Uint8Array {
- if (!something) return Uint8Array.from([0]); // empty
+// todo: add p2sh for xverse
+async function defaultUtxoToSpendable(
+ utxo: BlockstreamUtxo | BlockstreamUtxoWithTxHex
+): Promise<{ input: btc.TransactionInput; vsize?: number }> {
+ const utxoWithTx: BlockstreamUtxoWithTxHex =
+ 'hex' in utxo ? utxo : { ...utxo, hex: await api.fetchTxHex(utxo.txid) };
+
+ const tx = btc.Transaction.fromRaw(hexToBytes(utxoWithTx.hex), {
+ allowUnknownOutputs: true,
+ allowUnknownInputs: true,
+ });
+
+ const outputToSpend = tx.getOutput(utxo.vout);
+ if (!outputToSpend?.script) throw new Error('No script found on utxo tx');
+ const spendScript = btc.OutScript.decode(outputToSpend.script);
+
+ try {
+ if (spendScript.type !== 'wpkh') throw new Error('Non-p2wpkh utxo found');
- const bytes = fn(something);
- const length = bytes.byteLength;
- if (maxLength >= 0 && bytes.length > maxLength) {
- throw new Error(`ByteLength exceeds maximum length of ${maxLength}`);
+ const spendableInput: btc.TransactionInput = {
+ txid: hexToBytes(utxo.txid),
+ index: utxo.vout,
+ ...outputToSpend,
+ witnessUtxo: {
+ script: outputToSpend.script,
+ amount: BigInt(utxo.value),
+ },
+ };
+ new btc.Transaction().addInput(spendableInput); // validate, throws if invalid
+ return { input: spendableInput, vsize: VSIZE_INPUT_P2WPKH };
+ } catch (e) {
+ throw new Error(`Utxo doesn't match spendable type, ${JSON.stringify(utxo)}`);
}
- return concat(hex.length, bytes);
}
+// todo: after DR?
+// async function tryAllToSpendable(
+// utxo: BlockstreamUtxo | BlockstreamUtxoWithTxHex
+// ): Promise {
+// const utxoWithTx: BlockstreamUtxoWithTxHex =
+// 'hex' in utxo ? utxo : { ...utxo, hex: await fetchTxHex(utxo.txid) };
+
+// const tx = btc.Transaction.fromRaw(hexToBytes(utxoWithTx.hex), {
+// allowUnknownOutputs: true,
+// allowUnknownInputs: true,
+// });
+
+// const outputToSpend = tx.getOutput(utxo.vout);
+// if (!outputToSpend?.script) throw new Error('No script found on utxo tx');
+// const spendScript = btc.OutScript.decode(outputToSpend.script);
+
+// try {
+// switch (spendScript.type) {
+// case 'wpkh':
+// //
+// }
+// } catch (e) {
+// throw new Error(`Utxo doesn't match spendable type, ${JSON.stringify(utxo)}`);
+// }
+// }
+
+type UtxoToSpendableFn = (
+ utxo: BlockstreamUtxo | BlockstreamUtxoWithTxHex
+) => Promise<{ input: btc.TransactionInput; vsize?: number }>;
+
+export async function utxoSelect({
+ utxos,
+ utxoToSpendable = defaultUtxoToSpendable,
+ outputs,
+ feeRate,
+}: {
+ utxos: (BlockstreamUtxo | BlockstreamUtxoWithTxHex)[];
+ utxoToSpendable?: UtxoToSpendableFn;
+ outputs: btc.TransactionOutput[];
+ feeRate: number;
+}): Promise<{
+ inputs: btc.TransactionInput[];
+ outputs: btc.TransactionOutput[];
+ totalSats: bigint;
+ changeSats: bigint;
+}> {
+ const outputsValue = outputs.reduce(
+ (acc: bigint, o: btc.TransactionOutput) => acc + (o.amount ?? 0n),
+ 0n
+ );
+
+ const inputs: btc.TransactionInput[] = []; // collect inputs
+ let inputRunning = 0n;
+
+ let vsizeRunning = txBytes([], outputs);
+
+ for (const utxo of utxos) {
+ try {
+ const { input, vsize } = await utxoToSpendable(utxo);
+ const inputVsize = vsize ?? inputBytes(input);
+ const utxoFee = feeRate * inputVsize;
+
+ if (utxoFee > utxo.value) continue; // skip if utxo is too small to pay fee
+
+ // add input
+ inputs.push(input);
+ inputRunning += BigInt(utxo.value);
+ vsizeRunning += inputVsize;
+
+ // check if we have enough inputs
+ const fee = feeRate * vsizeRunning;
+ if (inputRunning >= outputsValue + BigInt(fee)) {
+ const changeSats = inputRunning - (outputsValue + BigInt(fee));
+ return { inputs, outputs, totalSats: inputRunning, changeSats };
+ }
+ } catch (e) {
+ continue; // skip if utxo is not spendable
+ }
+ }
+
+ throw new Error('Not enough funds');
+}
+
+/** */
+export const buildSbtcDepositTx = buildSbtcDepositTxOpReturn; // default to OP RETURN for developer release
+
+const SBTC_PEG_ADDRESS = 'tb1q3tj2fr9scwmcw3rq5m6jslva65f2rqjxt2t0zh'; // todo: auto-fetch or hardcode if final
/**
*
*/
-export function buildOpReturnDepositTransaction({
- network = NETWORK,
- amount,
- btcFeeRates,
- addressInfo,
+export function buildSbtcDepositTxOpReturn({
+ network = TEST_NETWORK, // default to testnet for developer release
+ amountSats,
stacksAddress,
- sbtcWalletAddress,
- cardinal,
- userPaymentPubKey,
-}: DepositOpts) {
- opts.network = opts.network ?? NETWORK; // mainnet by default
- const data = buildDepositPayloadOpReturn(network, stacksAddress);
- const txFees = calculateDepositFees(
- network,
- false,
- amount,
- btcFeeRates.feeInfo,
- addressInfo,
- sbtcWalletAddress,
- data
- );
+ pegAddress = SBTC_PEG_ADDRESS,
+}: {
+ network?: BitcoinNetwork;
+ amountSats: number;
+ stacksAddress: string;
+ pegAddress?: string;
+}) {
+ const data = buildSBtcDepositBtcPayload({ network, address: stacksAddress });
+
const tx = new btc.Transaction({
- allowUnknowInput: true,
- allowUnknowOutput: true,
+ // todo: disbale unknown
allowUnknownInputs: true,
allowUnknownOutputs: true,
});
- // no reveal fee for op_return
- addInputs(network, amount, 0, tx, false, addressInfo.utxos, userPaymentPubKey);
tx.addOutput({ script: btc.Script.encode(['RETURN', data]), amount: BigInt(0) });
- tx.addOutputAddress(sbtcWalletAddress, BigInt(amount), net);
- const changeAmount = inputAmt(tx) - (amount + txFees[1]);
- if (changeAmount > 0) tx.addOutputAddress(cardinal, BigInt(changeAmount), net);
+ tx.addOutputAddress(pegAddress, BigInt(amountSats), network);
+
return tx;
}
-/**
- * @param network
- * @param amount the amount to deposit plus the reveal transaction gas fee
- * @param btcFeeRates current rates
- * @param addressInfo the utxos to spend from
- * @param commitTxAddress the commitment address - contains the taproot data and the payload
- * @param cardinal the change address
- * @param userPaymentPubKey pubkey needed to spend script hash inputs
- * @returns transaction object
- */
-export function buildOpDropDepositTransaction(
- network: string,
- amount: number,
- btcFeeRates: any,
- addressInfo: any,
- commitTxAddress: string,
- cardinal: string,
- userPaymentPubKey: string
-) {
- const net = network === 'testnet' ? btc.TEST_NETWORK : btc.NETWORK;
- const txFees = calculateDepositFees(
- network,
- true,
- amount,
- btcFeeRates.feeInfo,
- addressInfo,
- commitTxAddress,
- undefined
- );
- const tx = new btc.Transaction({
- allowUnknowInput: true,
- allowUnknowOutput: true,
- allowUnknownInputs: true,
- allowUnknownOutputs: true,
- });
- addInputs(network, amount, REVEAL_PAYMENT, tx, false, addressInfo.utxos, userPaymentPubKey);
- tx.addOutputAddress(commitTxAddress, BigInt(amount), net);
- const changeAmount = inputAmt(tx) - (amount + txFees[1]);
- if (changeAmount > 0) tx.addOutputAddress(cardinal, BigInt(changeAmount), net);
+export async function sbtcDepositHelper({
+ network = TEST_NETWORK, // default to testnet for developer release
+ amountSats,
+ stacksAddress,
+ bitcoinChangeAddress,
+ utxos,
+ feeRate,
+ pegAddress = SBTC_PEG_ADDRESS,
+}: {
+ network?: BitcoinNetwork;
+ amountSats: number;
+ stacksAddress: string;
+ bitcoinChangeAddress: string;
+ utxos: (BlockstreamUtxo | BlockstreamUtxoWithTxHex)[];
+ feeRate: number;
+ pegAddress?: string;
+}) {
+ const tx = buildSbtcDepositTxOpReturn({ network, amountSats, stacksAddress, pegAddress });
+
+ // we separate this part, since wallets could handle it themselves
+ const pay = await paymentInfo({ tx, utxos, feeRate });
+ for (const input of pay.inputs) tx.addInput(input);
+ // for (const output of pay.outputs) tx.addOutput(output); // outputs are already on tx; todo: refactor?
+
+ const changeAfterAdditionalOutput = BigInt(VSIZE_INPUT_P2WPKH * feeRate) - pay.changeSats;
+ if (changeAfterAdditionalOutput > dustMinimum(VSIZE_INPUT_P2WPKH, feeRate)) {
+ tx.addOutputAddress(bitcoinChangeAddress, changeAfterAdditionalOutput, network);
+ }
+
return tx;
}
-export function getOpReturnDepositRequest(
- network: string,
- amount: number,
- commitKeys: any,
- stacksAddress: string,
- sbtcWalletAddress: string,
- cardinal: string
-): BridgeTransactionType {
- if (!stacksAddress) throw new Error('Stacks address missing');
- const data = buildDepositPayloadOpReturn(network, stacksAddress);
- //console.log('reclaimAddr.pubkey: ' + commitKeys.reclaimPubKey)
- //console.log('revealAddr.pubkey: ' + commitKeys.revealPubKey)
-
- const req: BridgeTransactionType = {
- originator: stacksAddress,
- fromBtcAddress: cardinal,
- revealPub: commitKeys.revealPubKey,
- reclaimPub: commitKeys.reclaimPubKey,
- status: 1,
- tries: 0,
- mode: 'op_return',
- amount: amount,
- requestType: 'deposit',
- wallet: hex.encode(data),
- stacksAddress: stacksAddress,
- sbtcWalletAddress: sbtcWalletAddress,
- };
- return req;
+export async function paymentInfo({
+ tx,
+ feeRate,
+ utxos,
+ utxoToSpendable = defaultUtxoToSpendable,
+}: {
+ tx: btc.Transaction;
+ feeRate: number;
+ utxos: (BlockstreamUtxo | BlockstreamUtxoWithTxHex)[];
+ utxoToSpendable?: UtxoToSpendableFn;
+}) {
+ const outputs = [];
+ for (let i = 0; i < tx.outputsLength; i++) {
+ outputs.push(tx.getOutput(i));
+ }
+
+ return await utxoSelect({ utxos, utxoToSpendable, outputs, feeRate });
}
-export function getOpDropDepositRequest(
- network: string,
- revealFee: number,
- commitKeys: any,
- stacksAddress: string,
- sbtcWalletAddress: string,
- cardinal: string
-): BridgeTransactionType {
- const net = network === 'testnet' ? btc.TEST_NETWORK : btc.NETWORK;
- if (!stacksAddress) throw new Error('Address needed');
- //console.log('reclaimAddr.pubkey: ' + commitKeys.reclaimPubKey)
- //console.log('revealAddr.pubkey: ' + commitKeys.revealPubKey)
-
- const data = buildData(network, stacksAddress, revealFee, true);
- const scripts = [
- { script: btc.Script.encode([data, 'DROP', hex.decode(commitKeys.revealPubKey), 'CHECKSIG']) },
- {
- script: btc.Script.encode([
- 'IF',
- 144,
- 'CHECKSEQUENCEVERIFY',
- 'DROP',
- hex.decode(commitKeys.reclaimPubKey),
- 'CHECKSIG',
- 'ENDIF',
- ]),
- },
- ];
- const script = btc.p2tr(btc.TAPROOT_UNSPENDABLE_KEY, scripts, net, true);
- const req: BridgeTransactionType = {
- originator: stacksAddress,
- fromBtcAddress: cardinal,
- revealPub: commitKeys.revealPubKey,
- reclaimPub: commitKeys.reclaimPubKey,
- status: 1,
- tries: 0,
- mode: 'op_drop',
- amount: revealFee,
- requestType: 'deposit',
- wallet:
- "p2tr(TAPROOT_UNSPENDABLE_KEY, [{ script: Script.encode([data, 'DROP', revealPubK, 'CHECKSIG']) }, { script: Script.encode([reclaimPubKey, 'CHECKSIG']) }], net, true)",
- stacksAddress: stacksAddress,
- sbtcWalletAddress: sbtcWalletAddress,
- };
- req.commitTxScript = toStorable(script);
- return req;
+const plus = (a: number, b: number) => a + b;
+
+function txBytes(inputs: btc.TransactionInput[], outputs: btc.TransactionOutput[]) {
+ return (
+ OVERHEAD_TX + inputs.map(inputBytes).reduce(plus, 0) + outputs.map(outputBytes).reduce(plus, 0)
+ );
}
-function buildData(
- network: string,
- sigOrPrin: string,
- revealFee: number,
- opDrop: boolean
-): Uint8Array {
- const net = network === 'testnet' ? btc.TEST_NETWORK : btc.NETWORK;
- if (opDrop) {
- return buildDepositPayload(net, revealFee, sigOrPrin, opDrop, undefined);
- }
- return buildDepositPayloadOpReturn(net, sigOrPrin);
+// todo: switch to estimating?
+
+function inputBytes(input: btc.TransactionInput) {
+ const tmpTx = new btc.Transaction({ allowUnknownInputs: true });
+ const originalSize = tmpTx.vsize;
+ tmpTx.addInput(input);
+ return tmpTx.vsize - originalSize;
+ // return OVERHEAD_INPUT + (input.finalScriptWitness ? input.finalScriptWitness.byteLength : OVERHEAD_INPUT_P2PKH);
}
-export function maxCommit(addressInfo: any) {
- if (!addressInfo || !addressInfo.utxos || addressInfo.utxos.length === 0) return 0;
- const summ = addressInfo?.utxos
- ?.map((item: { value: number }) => item.value)
- .reduce((prev: number, curr: number) => prev + curr, 0);
- return summ || 0;
+function outputBytes(output: btc.TransactionOutput) {
+ const tmpTx = new btc.Transaction({ allowUnknownOutputs: true });
+ const originalSize = tmpTx.vsize;
+ tmpTx.addOutput(output);
+ return tmpTx.vsize - originalSize;
+ // return OVERHEAD_OUTPUT + (output.script ? output.script.byteLength : OVERHEAD_OUTPUT_P2PKH);
}
-export function calculateDepositFees(
- network: string,
- opDrop: boolean,
- amount: number,
- feeInfo: any,
- addressInfo: any,
- commitTxScriptAddress: string,
- data: Uint8Array | undefined
-) {
- try {
- const net = network === 'testnet' ? btc.TEST_NETWORK : btc.NETWORK;
- let vsize = 0;
- const tx = new btc.Transaction({
- allowUnknowInput: true,
- allowUnknowOutput: true,
- allowUnknownInputs: true,
- allowUnknownOutputs: true,
- });
- addInputs(
- network,
- amount,
- REVEAL_PAYMENT,
- tx,
- true,
- addressInfo.utxos,
- hex.encode(secp.getPublicKey(privKey, true))
- );
- if (!opDrop) {
- if (data) tx.addOutput({ script: btc.Script.encode(['RETURN', data]), amount: BigInt(0) });
- tx.addOutputAddress(commitTxScriptAddress, BigInt(amount), net);
- } else {
- tx.addOutputAddress(commitTxScriptAddress, BigInt(amount), net);
- }
- const changeAmount = inputAmt(tx) - amount;
- if (changeAmount > 0) tx.addOutputAddress(addressInfo.address, BigInt(changeAmount), net);
- //tx.sign(privKey);
- //tx.finalize();
- vsize = tx.vsize;
- const fees = [
- Math.floor((vsize * feeInfo['low_fee_per_kb']) / 1024),
- Math.floor((vsize * feeInfo['medium_fee_per_kb']) / 1024),
- Math.floor((vsize * feeInfo['high_fee_per_kb']) / 1024),
- ];
- return fees;
- } catch (err: any) {
- return [850, 1000, 1150];
- }
+function dustMinimum(inputVsize: number, feeRate: number) {
+ return inputVsize * feeRate;
}
diff --git a/packages/sbtc/src/transactions/index.ts b/packages/sbtc/src/transactions/index.ts
new file mode 100644
index 000000000..23f5769d0
--- /dev/null
+++ b/packages/sbtc/src/transactions/index.ts
@@ -0,0 +1,3 @@
+export * from './api';
+export * from './deposit';
+export * from './constants';
diff --git a/packages/sbtc/tests/deposit.test.ts b/packages/sbtc/tests/deposit.test.ts
new file mode 100644
index 000000000..3e0c764ef
--- /dev/null
+++ b/packages/sbtc/tests/deposit.test.ts
@@ -0,0 +1,61 @@
+import { HDKey } from '@scure/bip32';
+import * as bip39 from '@scure/bip39';
+import * as btc from '@scure/btc-signer';
+import { describe, expect, test } from 'vitest';
+import { sbtcDepositHelper } from '../src';
+import * as api from '../src/transactions/api';
+
+describe('mock integration test', () => {
+ test('deposit', async () => {
+ // == Wallet ===================================================================
+ const seed = await bip39.mnemonicToSeed(
+ 'twice kind fence tip hidden tilt action fragile skin nothing glory cousin green tomorrow spring wrist shed math olympic multiply hip blue scout claw'
+ );
+
+ const TESTNET_VERSION = {
+ private: 0x00000000,
+ public: 0x043587cf,
+ };
+ const hdkey = HDKey.fromMasterSeed(seed, TESTNET_VERSION);
+
+ const chainCode = 1; // testnet = 1, mainnet = 0
+ const accountIndex = 0;
+ const path = `m/84'/${chainCode}'/${accountIndex}'/0/0`;
+
+ const privKey = hdkey.derive(path).privateKey!;
+ const address = btc.getAddress('wpkh', privKey, btc.TEST_NETWORK)!;
+
+ // == sBTC =====================================================================
+
+ const TARGET_STACKS_ADDRESS = 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM';
+
+ // Tx building (most simple interface)
+ const tx = await sbtcDepositHelper({
+ stacksAddress: TARGET_STACKS_ADDRESS,
+ amountSats: 1_000,
+
+ feeRate: await api.estimateFeeRate('low'),
+ utxos: await api.fetchUtxos(address),
+
+ bitcoinChangeAddress: address,
+ });
+
+ tx.sign(privKey);
+ tx.finalize();
+
+ expect(tx).toBeDefined(); // yay, it didn't throw
+ });
+});
+
+// api.broadcastTx(tx);
+
+// == Advanced =================================================================
+
+// const PEG_PUB_KEY = (
+// await api.stacksCallReadOnly({
+// contractAddress: "ST1R1061ZT6KPJXQ7PAXPFB6ZAZ6ZWW28G8HXK9G5.romeo-bridge",
+// functionName: "get-bitcoin-wallet-public-key",
+// sender: TARGET_STACKS_ADDRESS, // not actually used in call
+// })
+// ).value.buffer;
+// const PEG_ADDRESS = btc.p2tr(PEG_PUB_KEY, undefined, btc.TEST_NETWORK).address;
diff --git a/packages/sbtc/tsconfig.build.json b/packages/sbtc/tsconfig.build.json
index 8d57d415d..e6c63a0c7 100644
--- a/packages/sbtc/tsconfig.build.json
+++ b/packages/sbtc/tsconfig.build.json
@@ -11,9 +11,6 @@
{
"path": "../common/tsconfig.build.json"
},
- {
- "path": "../encryption/tsconfig.build.json"
- },
{
"path": "../network/tsconfig.build.json"
},
@@ -21,7 +18,5 @@
"path": "../transactions/tsconfig.build.json"
}
],
- "include": [
- "src/**/*"
- ]
+ "include": ["src/**/*"]
}
diff --git a/packages/sbtc/webpack.config.js b/packages/sbtc/webpack.config.js
index a41c22f84..9abb3d136 100644
--- a/packages/sbtc/webpack.config.js
+++ b/packages/sbtc/webpack.config.js
@@ -1,6 +1,6 @@
const config = require('../../configs/webpack.config.js');
-config.output.library.name = 'StacksStacking';
+config.output.library.name = 'StacksSbtc';
config.resolve.fallback = {};
diff --git a/vitest.config.ts b/vitest.config.ts
new file mode 100644
index 000000000..31e4d9e3c
--- /dev/null
+++ b/vitest.config.ts
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vitest/config';
+
+export default defineConfig({
+ test: {
+ testTimeout: process.env.CI ? 5_000 : 1_000_000,
+ },
+});